diff --git a/index.js b/index.js index 97bb595..882ea87 100644 --- a/index.js +++ b/index.js @@ -76,6 +76,10 @@ class DNS extends EventEmitter { resolvePTR(domain) { return this.resolve(domain, 'PTR'); } + + resolveDNSKEY(domain) { + return this.resolve(domain, 'DNSKEY'); + } } DNS.TCPServer = TCPServer; diff --git a/packet.js b/packet.js index 7df9b8e..56fa0fd 100644 --- a/packet.js +++ b/packet.js @@ -76,31 +76,32 @@ function Packet(data) { * @docs https://tools.ietf.org/html/rfc1035#section-3.2.2 */ Packet.TYPE = { - A : 0x01, - NS : 0x02, - MD : 0x03, - MF : 0x04, - CNAME : 0x05, - SOA : 0x06, - MB : 0x07, - MG : 0x08, - MR : 0x09, - NULL : 0x0A, - WKS : 0x0B, - PTR : 0x0C, - HINFO : 0x0D, - MINFO : 0x0E, - MX : 0x0F, - TXT : 0x10, - AAAA : 0x1C, - SRV : 0x21, - EDNS : 0x29, - SPF : 0x63, - AXFR : 0xFC, - MAILB : 0xFD, - MAILA : 0xFE, - ANY : 0xFF, - CAA : 0x101, + A : 0x01, + NS : 0x02, + MD : 0x03, + MF : 0x04, + CNAME : 0x05, + SOA : 0x06, + MB : 0x07, + MG : 0x08, + MR : 0x09, + NULL : 0x0A, + WKS : 0x0B, + PTR : 0x0C, + HINFO : 0x0D, + MINFO : 0x0E, + MX : 0x0F, + TXT : 0x10, + AAAA : 0x1C, + SRV : 0x21, + EDNS : 0x29, + SPF : 0x63, + AXFR : 0xFC, + MAILB : 0xFD, + MAILA : 0xFE, + ANY : 0xFF, + CAA : 0x101, + DNSKEY : 0x30, }; /** * [QUERY_CLASS description] @@ -830,6 +831,54 @@ Packet.Resource.CAA = { }, }; +/** + * @type {{decode: (function(*, *): Packet.Resource.DNSKEY)}} + * @link https://tools.ietf.org/html/rfc4034 + * @link https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml#table-dns-sec-alg-numbers-1 + */ +Packet.Resource.DNSKEY = { + decode: function(reader, length) { + const RData = []; + while (RData.length < length) { + RData.push(reader.read(8)); + } + this.flags = RData[0] << 8 | RData[1]; + this.protocol = RData[2]; + this.algorithm = RData[3]; + // for key tag + let ac = 0; + for (let i = 0; i < length; ++i) { + ac += (i & 1) ? RData[i] : RData[i] << 8; + } + ac += (ac >> 16) & 0xFFFF; + this.keyTag = ac & 0XFFFF; + + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 = 16 + // convert binary flags + let binFlags = this.flags.toString(2); + // add left padding until 16 chars + while (binFlags.length < 16) { + binFlags = '0' + binFlags; + } + this.zoneKey = binFlags[7] === '1'; + this.zoneSep = binFlags[15] === '1'; + this.key = Buffer.from(RData.slice(4)).toString('base64'); + return this; + }, + encode: function(record, writer) { + writer = writer || new Packet.Writer(); + const buffer = Buffer.from(record.key, 'base64'); + writer.write(4 + buffer.length, 16); + writer.write(record.flags, 16); + writer.write(record.protocol, 8); + writer.write(record.algorithm, 8); + buffer.forEach(function(c) { + writer.write(c, 8); + }); + return writer.toBuffer(); + }, +}; + Packet.Reader = BufferReader; Packet.Writer = BufferWriter; diff --git a/test/index.js b/test/index.js index 62b45ea..8e6461c 100644 --- a/test/index.js +++ b/test/index.js @@ -149,6 +149,21 @@ test('Packet#encode', function() { domain : 'sfo1.lsong.org', }); + // DNS KEY + response.answers.push({ + name : 'lsong.org', + ttl : 300, + type : 48, + class : 1, + flags : 256, + protocol : 3, + algorithm : 13, + keyTag : 1721, + zoneKey : true, + zoneSep : false, + key : 'PM8S6PI0Gf8d3HK9gHSVpW3X3zeieMEa+PLCijFuaFgiIANdUQen5xNn0/9+eo3E4VIJGU27lk6q4xXqMuQl7A==', + }); + response.authorities.push({ name : 'lsong.org', type : Packet.TYPE.MX,