From 7904e095e9f83c503eebd492db1cf7cf7bfaac5f Mon Sep 17 00:00:00 2001 From: Tom Pusateri Date: Sun, 4 Feb 2018 20:58:34 +0100 Subject: [PATCH] Add encoder for stream transports (TCP/TLS). (#23) * Add encoder for stream transports (TCP/TLS). Fixes #16. * Add README text and return null on short buffer. --- README.md | 6 +++++- example_tcp.js | 30 ++++++++++++++++++++++++++++++ index.js | 23 +++++++++++++++++++++++ test.js | 27 +++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 example_tcp.js diff --git a/README.md b/README.md index 45f0e20..5242c71 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ npm install dns-packet [![build status](https://travis-ci.org/mafintosh/dns-packet.svg?branch=master)](https://travis-ci.org/mafintosh/dns-packet) -## Usage +## UDP Usage ``` js var packet = require('dns-packet') @@ -35,6 +35,10 @@ socket.on('message', function (message) { socket.send(buf, 0, buf.length, 53, '8.8.8.8') ``` +## TCP Usage + +While DNS has traditionally been used over a datagram transport, it is increasingly being carried over TCP for larger responses commonly including DNSSEC responses and TCP/TLS for privacy reasons. + ## API #### `var buf = packets.encode(packet, [buf], [offset])` diff --git a/example_tcp.js b/example_tcp.js new file mode 100644 index 0000000..25e69c8 --- /dev/null +++ b/example_tcp.js @@ -0,0 +1,30 @@ +'use strict' + +const packet = require('./') +const net = require('net') + +const buf = packet.streamEncode({ + type: 'query', + id: 0xdead, + flags: packet.RECURSION_DESIRED, + questions: [{ + type: 'A', + name: 'google.com' + }] +}) + +const client = new net.Socket() +client.connect(53, '8.8.8.8', function () { + console.log('Connected') + client.write(buf) +}) + +client.on('data', function (data) { + console.log('Received response') + console.log(packet.streamDecode(data)) + client.destroy() // kill client after server's response +}) + +client.on('close', function () { + console.log('Connection closed') +}) diff --git a/index.js b/index.js index 94e9ae9..eff7871 100644 --- a/index.js +++ b/index.js @@ -811,6 +811,29 @@ exports.encodingLength = function (result) { encodingLengthList(result.additionals || [], answer) } +exports.streamEncode = function (result) { + const len = exports.encodingLength(result) + const buf = Buffer.allocUnsafe(len + 2) + exports.encode(result, buf, 2) + buf.writeUInt16BE(len, 0) + exports.streamEncode.bytes = len + 2 + return buf +} + +exports.streamEncode.bytes = 0 + +exports.streamDecode = function (buf) { + const len = buf.readUInt16BE(0) + if (buf.length < len + 2) { + return null + } + const result = exports.decode(buf, 2) + exports.streamDecode.bytes = exports.decode.bytes + 2 + return result +} + +exports.streamDecode.bytes = 0 + function encodingLengthList (list, enc) { let len = 0 for (let i = 0; i < list.length; i++) len += enc.encodingLength(list[i]) diff --git a/test.js b/test.js index 9813de8..d610ec1 100644 --- a/test.js +++ b/test.js @@ -289,6 +289,33 @@ tape('name_encoding', function (t) { t.end() }) +tape('stream', function (t) { + const val = { + type: 'query', + id: 45632, + flags: 0x8480, + answers: [{ + type: 'A', + name: 'test2.example.net', + data: '198.51.100.1' + }] + } + const buf = packet.streamEncode(val) + const val2 = packet.streamDecode(buf) + + t.same(buf.length, packet.streamEncode.bytes, 'streamEncode.bytes was set correctly') + t.same(packet.streamDecode.bytes, packet.streamEncode.bytes, 'streamDecode.bytes was set correctly') + t.ok(compare(t, val2.type, val.type), 'streamDecoded type match') + t.ok(compare(t, val2.id, val.id), 'streamDecoded id match') + t.ok(parseInt(val2.flags) === parseInt(val.flags & 0x7FFF), 'streamDecoded flags match') + const answer = val.answers[0] + const answer2 = val2.answers[0] + t.ok(compare(t, answer.type, answer2.type), 'streamDecoded RR type match') + t.ok(compare(t, answer.name, answer2.name), 'streamDecoded RR name match') + t.ok(compare(t, answer.data, answer2.data), 'streamDecoded RR rdata match') + t.end() +}) + function testEncoder (t, rpacket, val) { const buf = rpacket.encode(val) const val2 = rpacket.decode(buf)