dns.bend relies on unsafe/foreign
raw source on the hub · import bend-kit-dns@0.6.0.0/dns.bend as Dns
DNS codec and host lookup. Source: https://github.com/paymog/bend-kit/tree/main/dns
3 imports
import Base import bend-kit-wire@0.4.3.0/wire.bend as Wire import bend-kit-bytes@0.3.2.0/bytes.bend as Bytes
Types
type Step source · line 99 · raw
Data
One step through a name: continue at the next label or stop after the name.
GoStep
Stop@ok:Bool -> Step
type RR source · line 158 · raw
Data
RRBadRR
RRA@ip:String -> RR
RRSkipRR
type Try source · line 435 · raw
Data
One attempt's outcome: try again, or this answer (None: no address).
AgainTry
Got@ip:Maybe<&2, String> -> Try
Definitions
def label.ok source · line 13 · raw
@+l:String -> Bool
def label.ascii source · line 17 · raw
@s:String -> Bool
def labels.ok source · line 24 · raw
@xs:List<&2, String> -> Bool
def labels.len source · line 32 · raw
@xs:List<&2, String> -> @+n:U32 -> U32
QNAME's length without its final zero octet.
def written source · line 40 · raw
@r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Bool) -> 0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor
The query buffer is allocated to its exact size before writing.
def label.put source · line 44 · raw
@s:String -> @c:0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor -> 0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor
def labels.put source · line 51 · raw
@xs:List<&2, String> -> @c:0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor -> 0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor
def query.done source · line 58 · raw
@r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Bytes, U32) -> Maybe<&1, 0x185ae03c75e3e75be1171471f68b43cb/bytes.Bytes>
def query.if source · line 62 · raw
@+id:U32 -> @+xs:List<&2, String> -> @ok:Bool -> Maybe<&1, 0x185ae03c75e3e75be1171471f68b43cb/bytes.Bytes>
def query.labels source · line 78 · raw
@+id:U32 -> @+xs:List<&2, String> -> Maybe<&1, 0x185ae03c75e3e75be1171471f68b43cb/bytes.Bytes>
def strip_dot.if source · line 81 · raw
@+s:String -> @dot:Bool -> String
def strip_dot source · line 88 · raw
@+s:String -> String
def query source · line 92 · raw
@id:U32 -> @name:String -> Maybe<&1, 0x185ae03c75e3e75be1171471f68b43cb/bytes.Bytes>
RFC 1035 §4.1: a standard query for the A record of name.
def name.advance source · line 103 · raw
@stop:Bool -> @r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Bool) -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Step)
def name.label source · line 112 · raw
@ok:Bool -> @c:0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor -> @l:U32 -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Step)
§4.1.4: zero terminates, 192..255 starts a pointer, 64..191 is reserved.
def name.pointer source · line 119 · raw
@pointer:Bool -> @+l:U32 -> @c:0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Step)
def name.step.of source · line 126 · raw
@+l:U32 -> @c:0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Step)
def name.step source · line 133 · raw
@r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Maybe<&2, U32>) -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Step)
def name.walk source · line 141 · raw
@fuel:Nat -> @r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Step) -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Bool)
def name.skip source · line 155 · raw
@c:0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Bool)
§2.3.4: a name is at most 255 octets, so retain the 128-step limit.
def dotted source · line 163 · raw
@+ip:U32 -> String
def rr.a source · line 166 · raw
@limit:0x185ae03c75e3e75be1171471f68b43cb/bytes.CursorLimit -> @r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Maybe<&2, U32>) -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, RR)
def rr.data.some source · line 174 · raw
@a:Bool -> @c:0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor -> @limit:0x185ae03c75e3e75be1171471f68b43cb/bytes.CursorLimit -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, RR)
def rr.data source · line 182 · raw
@a:Bool -> @r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Maybe<&1, 0x185ae03c75e3e75be1171471f68b43cb/bytes.CursorLimit>) -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, RR)
Bound RDATA in the original packed buffer, then resume after the entire region.
def rr.len source · line 190 · raw
@+ty:U32 -> @+cl:U32 -> @r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Maybe<&2, U32>) -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, RR)
def rr.ttl source · line 198 · raw
@+ty:U32 -> @+cl:U32 -> @r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Bool) -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, RR)
def rr.cl source · line 206 · raw
@+ty:U32 -> @r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Maybe<&2, U32>) -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, RR)
def rr.ty source · line 214 · raw
@r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Maybe<&2, U32>) -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, RR)
def rr.name source · line 222 · raw
@r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Bool) -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, RR)
def rr source · line 231 · raw
@c:0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, RR)
§4.1.3: NAME, TYPE, CLASS, TTL, RDLENGTH, RDATA.
def answers.scan source · line 235 · raw
@fuel:Nat -> @r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, RR) -> Maybe<&2, String>
fuel = records left. The first A record wins; CNAMEs before it are skipped.
def question.end source · line 250 · raw
@r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Bool) -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Bool)
QTYPE and QCLASS follow the name.
def questions source · line 258 · raw
@fuel:Nat -> @r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Bool) -> Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Bool)
def body.go source · line 270 · raw
@+an:U32 -> @r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Bool) -> Maybe<&2, String>
def body.an source · line 279 · raw
@+qd:U32 -> @r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Maybe<&2, U32>) -> Maybe<&2, String>
The header ends with NSCOUNT and ARCOUNT; questions follow.
def body.qd source · line 287 · raw
@r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Maybe<&2, U32>) -> Maybe<&2, String>
def flags.ok source · line 296 · raw
@+f:U32 -> Bool
§4.1.1: QR set, opcode QUERY, not truncated, RCODE 0.
def head.flags.if source · line 299 · raw
@ok:Bool -> @c:0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor -> Maybe<&2, String>
def head.flags source · line 306 · raw
@r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Maybe<&2, U32>) -> Maybe<&2, String>
def head.id.if source · line 314 · raw
@ok:Bool -> @c:0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor -> Maybe<&2, String>
def head.id source · line 321 · raw
@+id:U32 -> @r:Pair(0x185ae03c75e3e75be1171471f68b43cb/bytes.Cursor, Maybe<&2, U32>) -> Maybe<&2, String>
def answer source · line 330 · raw
@id:U32 -> @msg:0x185ae03c75e3e75be1171471f68b43cb/bytes.Bytes -> Maybe<&2, String>
The IPv4 address the response gives for the query with this id.
def nameservers.add source · line 336 · raw
@+line:String -> @rest:List<&2, String> -> @hit:Bool -> List<&2, String>
def nameservers.go source · line 343 · raw
@xs:List<&2, String> -> List<&2, String>
def nameservers source · line 351 · raw
@conf:String -> List<&2, String>
Every nameserver line, in file order.
def nameserver.first source · line 354 · raw
@xs:List<&2, String> -> Maybe<&2, String>
def nameserver source · line 362 · raw
@conf:String -> Maybe<&2, String>
The first nameserver line of a resolv.conf.
def none source · line 368 · raw
IO(Maybe<&2, String>)
def list.append source · line 371 · raw
@xs:List<&2, String> -> @ys:List<&2, String> -> List<&2, String>
def list.one source · line 378 · raw
@+x:String -> List<&2, String>
def list.any source · line 381 · raw
@+xs:List<&2, String> -> Bool
def list.first source · line 388 · raw
@xs:List<&2, String> -> Maybe<&2, String>
def ipv4.go source · line 395 · raw
@s:String -> Bool
def ipv4 source · line 403 · raw
@+s:String -> Bool
Digits and dots; TCP.connect rejects anything else that is not an address.
def ipv6.ch source · line 406 · raw
@+c:U32 -> Bool
def ipv6.go source · line 413 · raw
@s:String -> Bool
def ipv6.has source · line 420 · raw
@s:String -> Bool
def ipv6 source · line 428 · raw
@+s:String -> Bool
Bracket-free IPv6 text; connect validates the address.
def ip source · line 431 · raw
@+s:String -> Bool
def try.pure source · line 439 · raw
@s:Socket -> @t:Try -> IO(Pair(Socket, Try))
def try.from source · line 443 · raw
@s:Socket -> @+ns:String -> @id:U32 -> @hpd:Pair(String, Pair(U32, Pair(U32, Array<U32>))) -> IO(Pair(Socket, Try))
A datagram from anyone but the nameserver's port 53 is ignored (retried).
def try.back source · line 448 · raw
@ns:String -> @id:U32 -> @m:Pair(Socket, Result<&1, &1, Pair(U32, String), Pair(String, Pair(U32, Pair(U32, Array<U32>)))>) -> IO(Pair(Socket, Try))
def try.sent source · line 457 · raw
@ns:String -> @id:U32 -> @m:Pair(Socket, Result<&1, &1, Pair(U32, String), Unit>) -> IO(Pair(Socket, Try))
§4.2.1 and resolv.conf defaults: 5 s per attempt.
def try.send source · line 468 · raw
@s:Socket -> @+ns:String -> @id:U32 -> @q:Maybe<&1, 0x185ae03c75e3e75be1171471f68b43cb/bytes.Bytes> -> IO(Pair(Socket, Try))
Bytes cannot be copied, so each attempt builds its own query. A name that query rejects ends the tries.
def try.once source · line 477 · raw
@s:Socket -> @+ns:String -> @+id:U32 -> @name:String -> IO(Pair(Socket, Try))
def try.close source · line 480 · raw
@s:Socket -> @r:Maybe<&2, String> -> IO(Maybe<&2, String>)
def tries.end source · line 485 · raw
@st:Pair(Socket, Try) -> IO(Maybe<&2, String>)
def tries source · line 494 · raw
@fuel:Nat -> @+ns:String -> @+id:U32 -> @+name:String -> @st:Pair(Socket, Try) -> IO(Maybe<&2, String>)
fuel: attempts left (resolv.conf's default is 2).
def resolve.sock source · line 508 · raw
@ns:String -> @id:U32 -> @name:String -> @r:Result<&1, &1, Pair(U32, String), Socket> -> IO(Maybe<&2, String>)
def resolve.id source · line 516 · raw
@name:String -> @ns:String -> @r:Result<&1, &1, Pair(U32, String), U32> -> IO(Maybe<&2, String>)
§7.3: a random id makes forged answers harder to land.
def resolve.ns source · line 525 · raw
@name:String -> @ns:Maybe<&2, String> -> IO(Maybe<&2, String>)
def resolve.at source · line 535 · raw
@+host:String -> @ns:String -> IO(Maybe<&2, String>)
Ask one nameserver. Tests use this; resolve reads /etc/resolv.conf.
def conf.text source · line 538 · raw
@r:Result<&1, &1, Pair(U32, String), String> -> String
def resolve.n3 source · line 546 · raw
@+name:String -> @xs:List<&2, String> -> IO(Maybe<&2, String>)
ponytail: 3 nameservers; a longer resolv.conf ignores the rest
def resolve.n2b source · line 553 · raw
@+name:String -> @rest:List<&2, String> -> @ip:Maybe<&2, String> -> IO(Maybe<&2, String>)
def resolve.n2 source · line 560 · raw
@+name:String -> @xs:List<&2, String> -> IO(Maybe<&2, String>)
def resolve.n1b source · line 569 · raw
@+name:String -> @rest:List<&2, String> -> @ip:Maybe<&2, String> -> IO(Maybe<&2, String>)
def resolve.list source · line 576 · raw
@+name:String -> @xs:List<&2, String> -> IO(Maybe<&2, String>)
def resolve.read source · line 585 · raw
@name:String -> @m:Pair(File, Result<&1, &1, Pair(U32, String), String>) -> IO(Maybe<&2, String>)
def resolve.conf source · line 591 · raw
@name:String -> @r:Result<&1, &1, Pair(U32, String), File> -> IO(Maybe<&2, String>)
def resolve.dns source · line 600 · raw
@name:String -> IO(Maybe<&2, String>)
def hosts.on_line source · line 606 · raw
@+name:String -> @ns:List<&2, String> -> Bool
def hosts.line.all source · line 613 · raw
@+name:String -> @xs:List<&2, String> -> List<&2, String>
def hosts.sp source · line 620 · raw
@+c:U32 -> @tab:Bool -> U32
def hosts.flat source · line 627 · raw
@s:String -> String
def hosts.scan.all source · line 634 · raw
@xs:List<&2, String> -> @+name:String -> @acc:List<&2, String> -> List<&2, String>
def hosts.all source · line 643 · raw
@+name:String -> @text:String -> List<&2, String>
Every address for name in an /etc/hosts file. The name is already lowercase.
def hosts source · line 647 · raw
@+name:String -> @text:String -> Maybe<&2, String>
First address for name in an /etc/hosts file. The name is already lowercase.
def lookup.split source · line 650 · raw
@+s:String -> List<&2, String>
def resolve.literal.all source · line 659 · raw
@+host:String -> List<&2, String>
Literals and localhost without the OS (for laws and fast paths).
def resolve.literal source · line 664 · raw
@+host:String -> Maybe<&2, String>
def resolve.all.got source · line 667 · raw
@r:Result<&1, &1, Pair(U32, String), String> -> IO(List<&2, String>)
def resolve.all.os source · line 674 · raw
@+name:String -> IO(List<&2, String>)
def resolve.all.dns.one source · line 679 · raw
@m:Maybe<&2, String> -> IO(List<&2, String>)
def resolve.all.dns source · line 687 · raw
@+name:String -> IO(List<&2, String>)
ponytail: UDP path still asks for A records only
def resolve.all.from source · line 692 · raw
@+name:String -> @+xs:List<&2, String> -> IO(List<&2, String>)
def resolve.all.text source · line 699 · raw
@+name:String -> @r:Result<&1, &1, Pair(U32, String), String> -> IO(List<&2, String>)
def resolve.all.opened source · line 706 · raw
@+name:String -> @m:Pair(File, Result<&1, &1, Pair(U32, String), String>) -> IO(List<&2, String>)
def resolve.all.hosts source · line 712 · raw
@+name:String -> @r:Result<&1, &1, Pair(U32, String), File> -> IO(List<&2, String>)
def resolve.all.pick source · line 721 · raw
@+host:String -> @+xs:List<&2, String> -> IO(List<&2, String>)
def resolve.all source · line 728 · raw
@+host:String -> IO(List<&2, String>)
def resolve.all.ask source · line 731 · raw
@+name:String -> IO(List<&2, String>)
def resolve.all.pure.pick source · line 736 · raw
@+host:String -> @+xs:List<&2, String> -> IO(List<&2, String>)
def resolve.all.pure source · line 743 · raw
@+host:String -> IO(List<&2, String>)
def resolve.pure source · line 746 · raw
@+host:String -> IO(Maybe<&2, String>)
def resolve source · line 752 · raw
@+host:String -> IO(Maybe<&2, String>)
First address from resolve.all (getaddrinfo order when the OS resolves).
Effects (foreign code)
effect lookup.all source · line 654 · raw
@host:String -> IO(Result<&1, &1, Pair(U32, String), String>)
OS resolver: every address, NUL-separated in getaddrinfo order.
foreign: effs/dns.c, effs/dns.js