ref: 6abd8d7e95c9df2553a69d6f88c82a9c935f6b4e
parent: cb17c0f4d27e5493a7c375c9b380bb5811d82244
author: Ori Bernstein <[email protected]>
date: Wed Dec 11 00:06:22 EST 2013
More work on DNS resolver.
--- a/libstd/resolve.myr
+++ b/libstd/resolve.myr
@@ -12,37 +12,34 @@
`Badhost
`Badsrv
`Badquery
+ `Badresp
;;
+ type netaddr = union
+ `Ipv4 byte[4]
+ `Ipv6 byte[16]
+ ;;
+
type hostinfo = struct
- flags : uint32
fam : sockfam
stype : socktype
+ ttl : uint32
+ addr : netaddr
+ /*
proto : uint32
+ flags : uint32
addr : sockaddr[:]
canon : byte[:]
next : hostinfo#
+ */
;;
- const resolve : (host : byte[:] -> hostinfo#)
+ const resolve : (host : byte[:] -> error(hostinfo[:], resolveerr))
;;
-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
+ /* FIXME: read /etc/hosts */
+ -> dnsresolve(host)
}
const dnsresolve = {host : byte[:]
@@ -55,10 +52,7 @@
if (nsrv = dnsconnect()) < 0
-> `Failure (`Badsrv)
;;
- if !dnsquery(nsrv, host)
- -> `Failure (`Badquery)
- ;;
- -> `Success true
+ -> dnsquery(nsrv, host)
}
const dnsconnect = {
@@ -71,7 +65,8 @@
put("Warning: Failed to open socket: %l\n", s)
-> -1
;;
- /* hardcode Google DNS for now */
+ /* hardcode Google DNS for now.
+ FIXME: parse /etc/resolv.conf */
sa.fam = Afinet
sa.port = hosttonet(53) /* port 53 */
sa.addr = [8,8,8,8] /* 8.8.8.8 */
@@ -84,10 +79,13 @@
}
const dnsquery = {srv, host
- tquery(srv, host)
- rquery(srv)
- put("Unimplemented query: srv=%z, host=%s\n", srv, host)
- -> false
+ var id
+ var r
+
+ id = tquery(srv, host)
+ r = rquery(srv, id)
+ put("Got hosts. Returning\n")
+ -> r
}
const Qr : uint16 = 1 << 0
@@ -96,14 +94,15 @@
const Rd : uint16 = 1 << 7
const Ra : uint16 = 1 << 8
-var nextid = 42
+var nextid : uint16 = 42
const tquery = {srv, host
var pkt : byte[512] /* big enough */
var off : size
+ put("Sending request for %s\n", host)
/* header */
off = 0
- off += pack16(pkt[:], off, nextid++) /* id */
+ off += pack16(pkt[:], off, nextid) /* id */
off += pack16(pkt[:], off, Ra) /* flags */
off += pack16(pkt[:], off, 1) /* qdcount */
off += pack16(pkt[:], off, 0) /* ancount */
@@ -115,11 +114,11 @@
off += pack16(pkt[:], off, 0x1) /* qtype: a record */
off += pack16(pkt[:], off, 0x1) /* qclass: inet4 */
- write(1, pkt[:off])
write(srv, pkt[:off])
+ -> nextid++
}
-const rquery = {srv
+const rquery = {srv, id
var pktbuf : byte[1024]
var pkt
var n
@@ -130,10 +129,56 @@
put("Warning: Failed to read from %z: %i\n", srv, n)
;;
pkt = pktbuf[:n]
+ put("Got response:\n");
dumpresponse(pkt)
+ -> hosts(pkt, id)
}
+const hosts = {pkt, id : uint16
+ var off
+ var v
+ var q
+ var a
+ var i
+ var hinf : hostinfo[:]
+ off = 0
+ /* parse header */
+ (v, off) = unpack16(pkt, off) /* id */
+ if v != id
+ -> `Failure (`Badresp)
+ ;;
+ put("Unpacking flags")
+ (v, off) = unpack16(pkt, off) /* flags */
+ (q, off) = unpack16(pkt, off) /* qdcount */
+ (a, off) = unpack16(pkt, off) /* ancount */
+ (v, off) = unpack16(pkt, off) /* nscount */
+ (v, off) = unpack16(pkt, off) /* arcount */
+
+ /* skip past query records */
+ for i = 0; i < q; i++
+ put("Skipping query record")
+ off = skipname(pkt, off) /* name */
+ (v, off) = unpack16(pkt, off) /* type */
+ (v, off) = unpack16(pkt, off) /* class */
+ ;;
+
+ /* parse answer records */
+ hinf = slalloc(a castto(size))
+ for i = 0; i < a; i++
+ off = skipname(pkt, off) /* name */
+ (v, off) = unpack16(pkt, off) /* type */
+ (v, off) = unpack16(pkt, off) /* class */
+ (hinf[i].ttl, off) = unpack32(pkt, off) /* ttl */
+ (v, off) = unpack16(pkt, off) /* rdatalen */
+ /* the thing we're interested in: our IP address */
+ hinf[i].addr = `Ipv4 [pkt[off], pkt[off+1], pkt[off+2], pkt[off+3]]
+ off += 4;
+ ;;
+ -> `Success hinf
+}
+
+
const dumpresponse = {pkt
var nquery
var nans
@@ -141,13 +186,8 @@
var v
var i
- put("packet size = %z\n", pkt.len)
(v, off) = unpack16(pkt, 0)
- put("hdr.id = %w\n", v)
(v, off) = unpack16(pkt, off)
- put("hdr.rawflag = %i\n", (((v castto(uint32)) & 0xf000) >> 12))
- put("hdr.flag = [Qr = %t, Aa = %t, Tc = %t, Rd = %t, Ra = %t]\n", (v&Qr) == 0, (v&Aa) == 0, (v&Tc) == 0, (v&Rd)==0, (v&Ra)==0)
- put("hdr.rcode = %w\n", (v >> 11) & 0xf)
(nquery, off) = unpack16(pkt, off)
put("hdr.qdcount = %w\n", nquery)
(nans, off) = unpack16(pkt, off)
@@ -203,6 +243,21 @@
-> off
}
+const skipname = {pkt, off
+ var sz
+
+ for sz = pkt[off] castto(size); sz != 0; sz = pkt[off] castto(size)
+ /* ptr is 2 bytes */
+ if sz & 0xC0 == 0xC0
+ -> off + 2
+ else
+ off += sz + 1
+ ;;
+ ;;
+ -> off + 1
+}
+
+
const printname = {pkt, off
var sz
@@ -231,6 +286,16 @@
v = (buf[off] castto(uint16)) << 8
v |= (buf[off + 1] castto(uint16))
-> (v, off+sizeof(uint16))
+}
+
+const unpack32 = {buf, off
+ var v
+
+ v = (buf[off] castto(uint32)) << 24
+ v |= (buf[off+1] castto(uint32)) << 32
+ v |= (buf[off+2] castto(uint32)) << 8
+ v |= (buf[off+3] castto(uint32))
+ -> (v, off+sizeof(uint32))
}
const packname = {buf, off : size, host