From eabaaa51567174d6d61504f96c2635aa2cf3c784 Mon Sep 17 00:00:00 2001 From: Tom Pusateri Date: Fri, 5 Jan 2018 12:46:20 -0500 Subject: [PATCH 1/7] Decode RCODE and other header flags. Fixes #11. --- index.js | 10 ++++++++++ package.json | 3 ++- rcodes.js | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 rcodes.js diff --git a/index.js b/index.js index be85d48..b66e442 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,5 @@ var types = require('./types') +var rcodes = require('./rcodes') var ip = require('ip') var Buffer = require('safe-buffer').Buffer @@ -126,6 +127,15 @@ header.decode = function (buf, offset) { id: buf.readUInt16BE(offset), type: flags & RESPONSE_FLAG ? 'response' : 'query', flags: flags & 32767, + opcode: (flags >> 11) & 0xf, + flag_auth: (flags >> 10) & 0x1, + flag_trunc: (flags >> 9) & 0x1, + flag_rd: (flags >> 8) & 0x1, + flag_ra: (flags >> 7) & 0x1, + flag_z: (flags >> 6) & 0x1, + flag_ad: (flags >> 5) & 0x1, + flag_cd: (flags >> 4) & 0x1, + rcode: rcodes.toString(flags & 0xf), questions: new Array(buf.readUInt16BE(offset + 4)), answers: new Array(buf.readUInt16BE(offset + 6)), authorities: new Array(buf.readUInt16BE(offset + 8)), diff --git a/package.json b/package.json index 736ba25..a0acdc4 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,8 @@ ], "files": [ "index.js", - "types.js" + "types.js", + "rcodes.js" ], "author": "Mathias Buus", "license": "MIT" diff --git a/rcodes.js b/rcodes.js new file mode 100644 index 0000000..4ca9db6 --- /dev/null +++ b/rcodes.js @@ -0,0 +1,48 @@ +/* + * Traditional DNS header RCODEs (4-bits) defined by IANA in + * https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml + */ + +exports.toString = function (rcode) { + switch (rcode) { + case 0: return 'NOERROR' + case 1: return 'FORMERR' + case 2: return 'SERVFAIL' + case 3: return 'NXDOMAIN' + case 4: return 'NOTIMP' + case 5: return 'REFUSED' + case 6: return 'YXDOMAIN' + case 7: return 'YXRRSET' + case 8: return 'NXRRSET' + case 9: return 'NOTAUTH' + case 10: return 'NOTZONE' + case 11: return 'RCODE_11' + case 12: return 'RCODE_12' + case 13: return 'RCODE_13' + case 14: return 'RCODE_14' + case 15: return 'RCODE_15' + } + return 'RCODE_' + type +} + +exports.toRcode = function (code) { + switch (code.toUpperCase()) { + case 'NOERROR': return 0 + case 'FORMERR': return 1 + case 'SERVFAIL': return 2 + case 'NXDOMAIN': return 3 + case 'NOTIMP': return 4 + case 'REFUSED': return 5 + case 'YXDOMAIN': return 6 + case 'YXRRSET': return 7 + case 'NXRRSET': return 8 + case 'NOTAUTH': return 9 + case 'NOTZONE': return 10 + case 'RCODE_11': return 11 + case 'RCODE_12': return 12 + case 'RCODE_13': return 13 + case 'RCODE_14': return 14 + case 'RCODE_15': return 15 + } + return 0 +} \ No newline at end of file From 9dad822ee8a87332060b210f64b2dd21567ef717 Mon Sep 17 00:00:00 2001 From: Tom Pusateri Date: Fri, 5 Jan 2018 14:02:39 -0500 Subject: [PATCH 2/7] Fix return code error and make lint happy. --- rcodes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rcodes.js b/rcodes.js index 4ca9db6..492b2f3 100644 --- a/rcodes.js +++ b/rcodes.js @@ -22,7 +22,7 @@ exports.toString = function (rcode) { case 14: return 'RCODE_14' case 15: return 'RCODE_15' } - return 'RCODE_' + type + return 'RCODE_' + rcode } exports.toRcode = function (code) { @@ -45,4 +45,4 @@ exports.toRcode = function (code) { case 'RCODE_15': return 15 } return 0 -} \ No newline at end of file +} From 0a0699cef6b825bcb61ba7f01798c1e3d10ddbc2 Mon Sep 17 00:00:00 2001 From: Tom Pusateri Date: Fri, 5 Jan 2018 16:09:26 -0500 Subject: [PATCH 3/7] Add rcode conversion tests. --- test.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test.js b/test.js index e8ef6b2..15edc12 100644 --- a/test.js +++ b/test.js @@ -1,5 +1,6 @@ var tape = require('tape') var packet = require('./') +var rcodes = require('./rcodes') var Buffer = require('safe-buffer').Buffer tape('unknown', function (t) { @@ -173,6 +174,14 @@ tape('response', function (t) { t.end() }) +tape('rcode', function (t) { + for (var rString of ['NOERROR', 'FORMERR', 'SERVFAIL', 'NXDOMAIN', 'NOTIMP', 'REFUSED', 'YXDOMAIN', 'YXRRSET', 'NXRRSET', 'NOTAUTH', 'NOTZONE', 'RCODE_11', 'RCODE_12', 'RCODE_13', 'RCODE_14', 'RCODE_15']) { + var code = rcodes.toRcode(rString) + t.ok(rString === rcodes.toString(code), 'rcode conversion from/to string matches: ' + rcodes.toString(code)) + } + t.end() +}) + function testEncoder (t, packet, val) { var buf = packet.encode(val) var val2 = packet.decode(buf) From b443e9f0cf07ffca4eb0c7364c79348ce70703ff Mon Sep 17 00:00:00 2001 From: Tom Pusateri Date: Fri, 5 Jan 2018 16:18:21 -0500 Subject: [PATCH 4/7] for..of won't work in node 0.10, switch to indexing into array. --- test.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test.js b/test.js index 15edc12..edc66c8 100644 --- a/test.js +++ b/test.js @@ -175,9 +175,10 @@ tape('response', function (t) { }) tape('rcode', function (t) { - for (var rString of ['NOERROR', 'FORMERR', 'SERVFAIL', 'NXDOMAIN', 'NOTIMP', 'REFUSED', 'YXDOMAIN', 'YXRRSET', 'NXRRSET', 'NOTAUTH', 'NOTZONE', 'RCODE_11', 'RCODE_12', 'RCODE_13', 'RCODE_14', 'RCODE_15']) { - var code = rcodes.toRcode(rString) - t.ok(rString === rcodes.toString(code), 'rcode conversion from/to string matches: ' + rcodes.toString(code)) + const errors = ['NOERROR', 'FORMERR', 'SERVFAIL', 'NXDOMAIN', 'NOTIMP', 'REFUSED', 'YXDOMAIN', 'YXRRSET', 'NXRRSET', 'NOTAUTH', 'NOTZONE', 'RCODE_11', 'RCODE_12', 'RCODE_13', 'RCODE_14', 'RCODE_15'] + for (var i in errors) { + var code = rcodes.toRcode(errors[i]) + t.ok(errors[i] === rcodes.toString(code), 'rcode conversion from/to string matches: ' + rcodes.toString(code)) } t.end() }) From 549d46e2416ef4a3738af73feaa5e13d492d2eaa Mon Sep 17 00:00:00 2001 From: Tom Pusateri Date: Fri, 5 Jan 2018 22:55:41 -0500 Subject: [PATCH 5/7] Add test for packet decode of header fields. --- test.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test.js b/test.js index edc66c8..a5ee614 100644 --- a/test.js +++ b/test.js @@ -180,6 +180,28 @@ tape('rcode', function (t) { var code = rcodes.toRcode(errors[i]) t.ok(errors[i] === rcodes.toString(code), 'rcode conversion from/to string matches: ' + rcodes.toString(code)) } + + var buf = packet.encode({ + type: 'response', + id: 45632, + flags: 0x8480, + answers: [{ + type: 'A', + name: 'hello.example.net', + data: '127.0.0.1' + }] + }) + var val = packet.decode(buf) + t.ok(val.type === 'response', 'decode type') + t.ok(val.opcode === 0, 'decode opcode') + t.ok(val.flag_auth === 1, 'decode flag_auth') + t.ok(val.flag_trunc === 0, 'decode flag_trunc') + t.ok(val.flag_rd === 0, 'decode flag_rd') + t.ok(val.flag_ra === 1, 'decode flag_ra') + t.ok(val.flag_z === 0, 'decode flag_z') + t.ok(val.flag_ad === 0, 'decode flag_ad') + t.ok(val.flag_cd === 0, 'decode flag_cd') + t.ok(val.rcode === 'NOERROR', 'decode rcode') t.end() }) From 2474fead8ffb7c5b5ad5fc78422448b52c162a51 Mon Sep 17 00:00:00 2001 From: Tom Pusateri Date: Sat, 6 Jan 2018 13:48:20 -0500 Subject: [PATCH 6/7] Add Q/R flag boolean and change other flags to boolean. --- index.js | 15 ++++++++------- test.js | 15 ++++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/index.js b/index.js index b66e442..72f9346 100644 --- a/index.js +++ b/index.js @@ -127,14 +127,15 @@ header.decode = function (buf, offset) { id: buf.readUInt16BE(offset), type: flags & RESPONSE_FLAG ? 'response' : 'query', flags: flags & 32767, + flag_qr: ((flags >> 15) & 0x1) === 1, opcode: (flags >> 11) & 0xf, - flag_auth: (flags >> 10) & 0x1, - flag_trunc: (flags >> 9) & 0x1, - flag_rd: (flags >> 8) & 0x1, - flag_ra: (flags >> 7) & 0x1, - flag_z: (flags >> 6) & 0x1, - flag_ad: (flags >> 5) & 0x1, - flag_cd: (flags >> 4) & 0x1, + flag_auth: ((flags >> 10) & 0x1) === 1, + flag_trunc: ((flags >> 9) & 0x1) === 1, + flag_rd: ((flags >> 8) & 0x1) === 1, + flag_ra: ((flags >> 7) & 0x1) === 1, + flag_z: ((flags >> 6) & 0x1) === 1, + flag_ad: ((flags >> 5) & 0x1) === 1, + flag_cd: ((flags >> 4) & 0x1) === 1, rcode: rcodes.toString(flags & 0xf), questions: new Array(buf.readUInt16BE(offset + 4)), answers: new Array(buf.readUInt16BE(offset + 6)), diff --git a/test.js b/test.js index a5ee614..996acad 100644 --- a/test.js +++ b/test.js @@ -194,13 +194,14 @@ tape('rcode', function (t) { var val = packet.decode(buf) t.ok(val.type === 'response', 'decode type') t.ok(val.opcode === 0, 'decode opcode') - t.ok(val.flag_auth === 1, 'decode flag_auth') - t.ok(val.flag_trunc === 0, 'decode flag_trunc') - t.ok(val.flag_rd === 0, 'decode flag_rd') - t.ok(val.flag_ra === 1, 'decode flag_ra') - t.ok(val.flag_z === 0, 'decode flag_z') - t.ok(val.flag_ad === 0, 'decode flag_ad') - t.ok(val.flag_cd === 0, 'decode flag_cd') + t.ok(val.flag_qr === true, 'decode flag_auth') + t.ok(val.flag_auth === true, 'decode flag_auth') + t.ok(val.flag_trunc === false, 'decode flag_trunc') + t.ok(val.flag_rd === false, 'decode flag_rd') + t.ok(val.flag_ra === true, 'decode flag_ra') + t.ok(val.flag_z === false, 'decode flag_z') + t.ok(val.flag_ad === false, 'decode flag_ad') + t.ok(val.flag_cd === false, 'decode flag_cd') t.ok(val.rcode === 'NOERROR', 'decode rcode') t.end() }) From 0e95e8e18d225d6f2abf78cce9357999c2a4cc6f Mon Sep 17 00:00:00 2001 From: Tom Pusateri Date: Sat, 6 Jan 2018 14:08:41 -0500 Subject: [PATCH 7/7] Convert Opcodes to/from strings. --- index.js | 3 ++- opcodes.js | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 ++- test.js | 9 ++++++++- 4 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 opcodes.js diff --git a/index.js b/index.js index 72f9346..aeab452 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ var types = require('./types') var rcodes = require('./rcodes') +var opcodes = require('./opcodes') var ip = require('ip') var Buffer = require('safe-buffer').Buffer @@ -128,7 +129,7 @@ header.decode = function (buf, offset) { type: flags & RESPONSE_FLAG ? 'response' : 'query', flags: flags & 32767, flag_qr: ((flags >> 15) & 0x1) === 1, - opcode: (flags >> 11) & 0xf, + opcode: opcodes.toString((flags >> 11) & 0xf), flag_auth: ((flags >> 10) & 0x1) === 1, flag_trunc: ((flags >> 9) & 0x1) === 1, flag_rd: ((flags >> 8) & 0x1) === 1, diff --git a/opcodes.js b/opcodes.js new file mode 100644 index 0000000..6b42db3 --- /dev/null +++ b/opcodes.js @@ -0,0 +1,48 @@ +/* + * Traditional DNS header OPCODEs (4-bits) defined by IANA in + * https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-5 + */ + +exports.toString = function (opcode) { + switch (opcode) { + case 0: return 'QUERY' + case 1: return 'IQUERY' + case 2: return 'STATUS' + case 3: return 'OPCODE_3' + case 4: return 'NOTIFY' + case 5: return 'UPDATE' + case 6: return 'OPCODE_6' + case 7: return 'OPCODE_7' + case 8: return 'OPCODE_8' + case 9: return 'OPCODE_9' + case 10: return 'OPCODE_10' + case 11: return 'OPCODE_11' + case 12: return 'OPCODE_12' + case 13: return 'OPCODE_13' + case 14: return 'OPCODE_14' + case 15: return 'OPCODE_15' + } + return 'OPCODE_' + opcode +} + +exports.toOpcode = function (code) { + switch (code.toUpperCase()) { + case 'QUERY': return 0 + case 'IQUERY': return 1 + case 'STATUS': return 2 + case 'OPCODE_3': return 3 + case 'NOTIFY': return 4 + case 'UPDATE': return 5 + case 'OPCODE_6': return 6 + case 'OPCODE_7': return 7 + case 'OPCODE_8': return 8 + case 'OPCODE_9': return 9 + case 'OPCODE_10': return 10 + case 'OPCODE_11': return 11 + case 'OPCODE_12': return 12 + case 'OPCODE_13': return 13 + case 'OPCODE_14': return 14 + case 'OPCODE_15': return 15 + } + return 0 +} diff --git a/package.json b/package.json index a0acdc4..5f646d3 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,8 @@ "files": [ "index.js", "types.js", - "rcodes.js" + "rcodes.js", + "opcodes.js" ], "author": "Mathias Buus", "license": "MIT" diff --git a/test.js b/test.js index 996acad..fad0ddc 100644 --- a/test.js +++ b/test.js @@ -1,6 +1,7 @@ var tape = require('tape') var packet = require('./') var rcodes = require('./rcodes') +var opcodes = require('./opcodes') var Buffer = require('safe-buffer').Buffer tape('unknown', function (t) { @@ -181,6 +182,12 @@ tape('rcode', function (t) { t.ok(errors[i] === rcodes.toString(code), 'rcode conversion from/to string matches: ' + rcodes.toString(code)) } + const ops = ['QUERY', 'IQUERY', 'STATUS', 'OPCODE_3', 'NOTIFY', 'UPDATE', 'OPCODE_6', 'OPCODE_7', 'OPCODE_8', 'OPCODE_9', 'OPCODE_10', 'OPCODE_11', 'OPCODE_12', 'OPCODE_13', 'OPCODE_14', 'OPCODE_15'] + for (i in ops) { + code = opcodes.toOpcode(ops[i]) + t.ok(ops[i] === opcodes.toString(code), 'opcode conversion from/to string matches: ' + opcodes.toString(code)) + } + var buf = packet.encode({ type: 'response', id: 45632, @@ -193,7 +200,7 @@ tape('rcode', function (t) { }) var val = packet.decode(buf) t.ok(val.type === 'response', 'decode type') - t.ok(val.opcode === 0, 'decode opcode') + t.ok(val.opcode === 'QUERY', 'decode opcode') t.ok(val.flag_qr === true, 'decode flag_auth') t.ok(val.flag_auth === true, 'decode flag_auth') t.ok(val.flag_trunc === false, 'decode flag_trunc')