ref: 0332d1906fe2722d135ecff3466142f2d4703c11
dir: /libstd/resolve.myr/
use "alloc.use"
use "die.use"
use "endian.use"
use "error.use"
use "fmt.use"
use "slcp.use"
use "sys.use"
use "types.use"
pkg std =
type resolveerr = union
`Badhost
`Badsrv
`Badquery
;;
type hostinfo = struct
flags : uint32
fam : sockfam
stype : socktype
proto : uint32
addr : sockaddr[:]
canon : byte[:]
next : hostinfo#
;;
const resolve : (host : byte[:] -> hostinfo#)
;;
type dnshdr = struct
id : uint16
/* {qr:1|op:4|aa:1|tc:1|rd:1|ra:1|z:3|rcode:4} */
flags : uint16
qdcnt : uint16
ancnt : uint16
nscnt : uint16
arcnt : uint16
;;
const resolve = {host : byte[:]
var hinf
hinf = zalloc()
dnsresolve(host)
-> hinf
}
const dnsresolve = {host : byte[:]
/*var hosts*/
var nsrv
if !valid(host)
-> `Failure (`Badhost)
;;
if (nsrv = dnsconnect()) < 0
-> `Failure (`Badsrv)
;;
if !dnsquery(nsrv, host)
-> `Failure (`Badquery)
;;
-> `Success true
}
const dnsconnect = {
var sa : sockaddr_in
var s
var status
s = socket(Afinet, Sockdgram, 0)
if s < 0
put("Warning: Failed to open socket: %l\n", s)
-> -1
;;
/* hardcode Google DNS for now */
sa.fam = Afinet
sa.port = hosttonet(53)
sa.addr = 0x08080808
status = connect(s, (&sa) castto(sockaddr#), sizeof(sockaddr_in))
if status < 0
put("Warning: Failed to connect to server: %l\n", status)
-> -1
;;
-> s
}
const dnsquery = {srv, host
tquery(srv, host)
rquery(srv)
put("Unimplemented query: srv=%z, host=%s\n", srv, host)
-> false
}
const Qr : uint16 = 1 << 0
const Aa : uint16 = 1 << 4
const Tc : uint16 = 1 << 5
const Rd : uint16 = 1 << 6
const Ra : uint16 = 1 << 7
var nextid = 0
const tquery = {srv, host
var pkt : byte[512] /* big enough */
var off
/* header */
off = 0
off += pack16(pkt[:], off, nextid++) /* id */
off += pack16(pkt[:], off, Qr|Ra|Rd) /* flags */
off += pack16(pkt[:], off, 1) /* qdcount */
off += pack16(pkt[:], off, 0) /* ancount */
off += pack16(pkt[:], off, 0) /* nscount */
off += pack16(pkt[:], off, 0) /* arcount */
/* query */
off += packname(pkt[:], off, host) /* host */
off += pack16(pkt[:], off, 0x1) /* qtype: a record */
off += pack16(pkt[:], off, 0x1) /* qclass: inet4 */
write(srv, pkt[:off])
}
const rquery = {srv
var pktbuf : byte[1024]
var n
n = read(srv, pktbuf[:])
if n < 0
put("Warning: Failed to read from %z: %i\n", srv, n)
;;
put("pkt: [len = %z]: %s\n", n, pktbuf[:n])
}
const pack16 = {buf, off, v
buf[off] = (v & 0xff00) >> 8 castto(byte)
buf[off+1] = (v & 0x00ff) castto(byte)
-> sizeof(uint16) /* we always write one uint16 */
}
/*
const unpack16 = {buf, off
var v
v = (buf[off] castto(uint16)) << 8
v |= (buf[off + 1] castto(uint16))
-> (v, sizeof(uint16))
}
*/
const packname = {buf, off, host
var i
var start
var seglen
var lastseg
start = off
lastseg = 0
for i = 0; i < host.len; i++
if host[i] == ('.' castto(byte))
off += addseg(buf, off, host[lastseg:lastseg+seglen])
lastseg = seglen + 1
seglen = 0
;;
seglen++
;;
if host[host.len - 1] != ('.' castto(byte))
off += addseg(buf, off, host[lastseg:lastseg + seglen])
;;
off += addseg(buf, off, "") /* null terminating segment */
put("size: %z\n", off - start)
-> off - start
}
const addseg = {buf, off, str
put("Adding seg %s\n", str)
buf[0] = str.len castto(byte)
slcp(buf[off + 1 : off + str.len + 1], str)
-> str.len
}
const valid = {host : byte[:]
var i
var seglen
/* maximum length: 255 chars */
if host.len > 255
-> false
;;
seglen = 0
for i = 0; i < host.len; i++
if host[i] == ('.' castto(byte))
seglen = 0
;;
if seglen > 63
-> false
;;
if host[i] & 0x80
-> false
;;
;;
-> true
}