Skip to content

Commit

Permalink
Merge pull request #17 from pusateri/rcode
Browse files Browse the repository at this point in the history
Add support for RCODE and other header flag decoding.
  • Loading branch information
silverwind committed Jan 10, 2018
2 parents 5aaf079 + 0e95e8e commit 424f9e8
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 1 deletion.
12 changes: 12 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
var types = require('./types')
var rcodes = require('./rcodes')
var opcodes = require('./opcodes')
var ip = require('ip')
var Buffer = require('safe-buffer').Buffer

Expand Down Expand Up @@ -126,6 +128,16 @@ 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: opcodes.toString((flags >> 11) & 0xf),
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)),
authorities: new Array(buf.readUInt16BE(offset + 8)),
Expand Down
48 changes: 48 additions & 0 deletions opcodes.js
Original file line number Diff line number Diff line change
@@ -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
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@
],
"files": [
"index.js",
"types.js"
"types.js",
"rcodes.js",
"opcodes.js"
],
"author": "Mathias Buus",
"license": "MIT"
Expand Down
48 changes: 48 additions & 0 deletions rcodes.js
Original file line number Diff line number Diff line change
@@ -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_' + rcode
}

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
}
40 changes: 40 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,5 +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) {
Expand Down Expand Up @@ -173,6 +175,44 @@ tape('response', function (t) {
t.end()
})

tape('rcode', function (t) {
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))
}

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,
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 === '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')
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()
})

function testEncoder (t, packet, val) {
var buf = packet.encode(val)
var val2 = packet.decode(buf)
Expand Down

0 comments on commit 424f9e8

Please sign in to comment.