From ff1fb155312b1c829beacf77e97996b58caf3159 Mon Sep 17 00:00:00 2001 From: dschmenk Date: Sat, 31 Oct 2015 17:01:01 -0700 Subject: [PATCH] Working DNS resolution --- src/libsrc/dhcp.pla | 4 +- src/libsrc/inet.pla | 200 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 177 insertions(+), 27 deletions(-) diff --git a/src/libsrc/dhcp.pla b/src/libsrc/dhcp.pla index 6932c68..ff89ae1 100644 --- a/src/libsrc/dhcp.pla +++ b/src/libsrc/dhcp.pla @@ -255,7 +255,9 @@ loop iNet:closeUDP(portDHCP) iNet:setInterfaceIP(@localip, @localnet, @localgw) puts(@boundstr);putip(@localip);putc('/');putip(@localnet);putln -iNet:setDNS(@localdns) +if localdns:0 | localdns:2 + iNet:setDNS(@localdns) +fin puts(@dnsstr);putip(@localdns);putln done diff --git a/src/libsrc/inet.pla b/src/libsrc/inet.pla index e87cb78..73aa6b2 100644 --- a/src/libsrc/inet.pla +++ b/src/libsrc/inet.pla @@ -28,6 +28,17 @@ struc t_inet word resolveIP end // +// DNS message +// +struc t_dnshdr + word dnsID + word dnsCode + word dnsQdCount + word dnsAnCount + word dnsNsCount + word dnsArCount +end +// // External interface to net class. Must be first. // export byte[t_inet] iNet @@ -39,35 +50,56 @@ byte = "UTHERNET" byte = "" word driver = @netDrivers // -// DNS address +// DNS address (default to Google DNS) // -byte[4] dns - -export def iNetInit - // - // Look for net hardware - // - while ^driver - //puts(driver);putln - if modexec(driver) >= 0 - break - fin - driver = driver + ^driver + 1 - loop - if !^driver - return 0 - fin - // - // Get an IP address - // - modexec("DHCP") - return @iNet -end +byte[4] dns = 8,8,8,8 +const DNS_QUERY = 1 +const DNS_ANSWER = 2 +byte stateDNS def iNetSetDNS(ipptr) return memcpy(@dns, ipptr, 4) end +def putln + return putc($0D) +end +def putb(hexb) + return call($FDDA, hexb, 0, 0, 0) +end +def puth(hex) + return call($F941, hex >> 8, hex, 0, 0) +end +def puti(i) + if i < 0; putc('-'); i = -i; fin + if i < 10 + putc(i + '0') + else + puti(i / 10) + putc(i % 10 + '0') + fin +end +def putip(ipptr) + byte i + + for i = 0 to 2 + puti(ipptr->[i]); putc('.') + next + return puti(ipptr->[i]) +end +def dumpbytes(buf, len) + word i + + for i = 0 to len - 1 + putb(buf->[i]) + if i & 7 == 7 + putln + else + putc(' ') + fin + next +end + def parseIP(ipstr, ipaddr) byte i word endstr @@ -86,21 +118,137 @@ def parseIP(ipstr, ipaddr) return i == 3 end +def parseDomain(domstr, msgptr) + byte i, l + + l = 0 + for i = 1 to ^domstr + if domstr->[i] == '.' + msgptr->[l] = i - l - 1 + l = i + else + msgptr->[i] = domstr->[i] + fin + next + msgptr->[l] = i - l - 1 + msgptr = msgptr + i + ^msgptr = 0 // Terminate label list + return msgptr + 1 +end + +def recvDNS(remip, remport, pkt, len, ipaddr) + byte q, r + word resptr + + if pkt=>dnsID == $BEEF + q = pkt->dnsQdCount.1 + r = pkt->dnsAnCount.1 + pkt->dnsNsCount.1 + pkt->dnsArCount.1 + resptr = pkt + t_dnshdr + while q + while ^resptr + //puts(resptr); putc('.') + resptr = resptr + ^resptr + 1 + loop + resptr = resptr + 1 + //putln; dumpbytes(resptr, 4); putln + resptr = resptr + 4 + q = q - 1 + loop + while r + //dumpbytes(resptr, 40); putln + if ^resptr & $C0 == $C0 + resptr = resptr + 2 + else + while ^resptr + //puts(resptr); putc('.') + resptr = resptr + ^resptr + 1 + loop + resptr = resptr + 1 + fin + if resptr->1 == 1 and resptr->3 == 1 and resptr->9 == 4 + ipaddr=>0 = resptr=>10 + ipaddr=>2 = resptr=>12 + fin + //putln; dumpbytes(resptr, 10); putc(':'); putln + resptr = resptr + 8 + //dumpbytes(resptr + 2, ^(resptr + 1)) + resptr = resptr + 2 + ^(resptr + 1); putln + r = r - 1 + loop + fin + stateDNS = DNS_ANSWER +end + def iNetResolve(namestr, ipaddr) + word dnspkt, msgptr, msglen + word portDNS, timeout + ipaddr=>0 = 0 ipaddr=>2 = 0 if not parseIP(namestr, ipaddr) // // Query Domain Name Server for address // + dnspkt = heapmark // Use heap as working DNS query packet + msgptr = dnspkt + msgptr=>dnsID = $BEEF + msgptr=>dnsCode = $0001 // RD (Recursion Desired) + msgptr=>dnsQdCount = $0100 // BE count = 1 + msgptr=>dnsAnCount = 0 + msgptr=>dnsNsCount = 0 + msgptr=>dnsArCount = 0 + msgptr = parseDomain(namestr, msgptr + t_dnshdr) + msgptr=>0 = $0100 // BE TYPE = Address + msgptr=>2 = $0100 // BE CLASS = INternet + msglen = msgptr - dnspkt + 4 + heapalloc(msglen) + // + // Prepare to receive DNS answer from server + // + portDNS = iNet:openUDP(3999, @recvDNS, ipaddr) + // + // Service IP + // + stateDNS = DNS_QUERY + iNet:sendUDP(portDNS, @dns, 53, dnspkt, msglen) + for timeout = 1 to 1000 + iNet:serviceIP() + if stateDNS == DNS_ANSWER + break + fin + next + iNet:closeUDP(portDNS) + heaprelease(dnspkt) fin - return 1 + return ipaddr=>0 <> 0 or ipaddr=>2 <> 0 +end + +export def iNetInit + // + // Look for net hardware + // + while ^driver + //puts(driver);putln + if modexec(driver) >= 0 + break + fin + driver = driver + ^driver + 1 + loop + if !^driver + return 0 + fin + // + // Get an IP address + // + modexec("DHCP") + iNet:resolveIP = @iNetResolve + return @iNet end // -// Fill iNet +// Fill iNet class +// iNet:initIP = @iNetInit iNet:setDNS = @iNetSetDNS -iNet:resolveIP = @iNetResolve done