Compare commits
No commits in common. "a260a8386b2d837eaf3c3406d8b0e4edf620beb6" and "dfe5e3f86bb6537963b1878eee7733277effb47e" have entirely different histories.
a260a8386b
...
dfe5e3f86b
@ -12,9 +12,6 @@ exports.toString = function (klass) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exports.toClass = function (name) {
|
exports.toClass = function (name) {
|
||||||
if (typeof name === 'number') {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
switch (name.toUpperCase()) {
|
switch (name.toUpperCase()) {
|
||||||
case 'IN': return 1
|
case 'IN': return 1
|
||||||
case 'CS': return 2
|
case 'CS': return 2
|
||||||
|
|||||||
65
hexdump.js
65
hexdump.js
@ -1,65 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const wout = (s) => {
|
|
||||||
process.stdout.write(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
const padStr = (s, len, ch) => {
|
|
||||||
ch = ch || ' '
|
|
||||||
while (s.length < len) {
|
|
||||||
s = ch + s
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
const hexDigit = (n, len) => {
|
|
||||||
return padStr(n.toString(16), len || 2, '0')
|
|
||||||
}
|
|
||||||
|
|
||||||
const printableCh = (c) => {
|
|
||||||
// [space to '~')
|
|
||||||
if (c > 0x20 && c <= 0x7e) {
|
|
||||||
return String.fromCharCode(c)
|
|
||||||
} else {
|
|
||||||
return '.'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const hexdump = (buf, len) => {
|
|
||||||
len = len || buf.length
|
|
||||||
|
|
||||||
const maxline = 16
|
|
||||||
let ascii = new Array(maxline)
|
|
||||||
let i
|
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
if (i % maxline === 0) {
|
|
||||||
if (i > 0) {
|
|
||||||
wout(' ' + ascii.join(''))
|
|
||||||
wout('\n')
|
|
||||||
}
|
|
||||||
wout(hexDigit(i, 4) + ': ')
|
|
||||||
}
|
|
||||||
|
|
||||||
// output the hex digit
|
|
||||||
wout(hexDigit(buf[i]))
|
|
||||||
wout(' ')
|
|
||||||
ascii[i % maxline] = printableCh(buf[i])
|
|
||||||
}
|
|
||||||
if (i % maxline !== 0) {
|
|
||||||
let diff = maxline - (i % maxline)
|
|
||||||
wout(' '.repeat(diff))
|
|
||||||
}
|
|
||||||
|
|
||||||
wout(' ' + ascii.slice(0, (i % maxline)).join('') + '\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
let buf = Buffer.alloc(500)
|
|
||||||
for (let i = 0; i < buf.length; i++) {
|
|
||||||
buf[i] = i & 0xff
|
|
||||||
}
|
|
||||||
hexdump(buf)
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = hexdump
|
|
||||||
391
index.js
391
index.js
@ -13,6 +13,7 @@ const RESPONSE_FLAG = 1 << 15
|
|||||||
const FLUSH_MASK = 1 << 15
|
const FLUSH_MASK = 1 << 15
|
||||||
const NOT_FLUSH_MASK = ~FLUSH_MASK
|
const NOT_FLUSH_MASK = ~FLUSH_MASK
|
||||||
const QU_MASK = 1 << 15
|
const QU_MASK = 1 << 15
|
||||||
|
const NOT_QU_MASK = ~QU_MASK
|
||||||
|
|
||||||
const name = exports.name = {}
|
const name = exports.name = {}
|
||||||
|
|
||||||
@ -1473,390 +1474,6 @@ rtlsa.encodingLength = function (cert) {
|
|||||||
return 5 + Buffer.byteLength(cert.certificate)
|
return 5 + Buffer.byteLength(cert.certificate)
|
||||||
}
|
}
|
||||||
|
|
||||||
const svcparam = exports.svcparam = {}
|
|
||||||
|
|
||||||
svcparam.keyToNumber = function (keyName) {
|
|
||||||
switch (keyName.toLowerCase()) {
|
|
||||||
case 'mandatory': return 0
|
|
||||||
case 'alpn' : return 1
|
|
||||||
case 'no-default-alpn' : return 2
|
|
||||||
case 'port' : return 3
|
|
||||||
case 'ipv4hint' : return 4
|
|
||||||
case 'echconfig' : return 5
|
|
||||||
case 'ipv6hint' : return 6
|
|
||||||
case 'dohpath' : return 7
|
|
||||||
case 'odoh' : return 32769
|
|
||||||
case 'key65535' : return 65535
|
|
||||||
}
|
|
||||||
if (!keyName.startsWith('key')) {
|
|
||||||
throw new Error(`Name must start with key: ${keyName}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return Number.parseInt(keyName.substring(3))
|
|
||||||
}
|
|
||||||
|
|
||||||
svcparam.numberToKeyName = function (number) {
|
|
||||||
switch (number) {
|
|
||||||
case 0 : return 'mandatory'
|
|
||||||
case 1 : return 'alpn'
|
|
||||||
case 2 : return 'no-default-alpn'
|
|
||||||
case 3 : return 'port'
|
|
||||||
case 4 : return 'ipv4hint'
|
|
||||||
case 5 : return 'echconfig'
|
|
||||||
case 6 : return 'ipv6hint'
|
|
||||||
case 7 : return 'dohpath'
|
|
||||||
case 32769 : return 'odoh'
|
|
||||||
}
|
|
||||||
|
|
||||||
return `key${number}`
|
|
||||||
}
|
|
||||||
|
|
||||||
svcparam.encode = function (param, buf, offset) {
|
|
||||||
if (!buf) buf = Buffer.allocUnsafe(svcparam.encodingLength(param))
|
|
||||||
if (!offset) offset = 0
|
|
||||||
|
|
||||||
let key = param.key
|
|
||||||
if (typeof param.key !== 'number') {
|
|
||||||
key = svcparam.keyToNumber(param.key)
|
|
||||||
}
|
|
||||||
buf.writeUInt16BE(key || 0, offset)
|
|
||||||
offset += 2
|
|
||||||
svcparam.encode.bytes = 2
|
|
||||||
|
|
||||||
if (key === 0) { // mandatory
|
|
||||||
let values = param.value
|
|
||||||
if (!Array.isArray(values)) values = [values]
|
|
||||||
buf.writeUInt16BE(values.length * 2, offset)
|
|
||||||
offset += 2
|
|
||||||
svcparam.encode.bytes += 2
|
|
||||||
|
|
||||||
for (let val of values) {
|
|
||||||
if (typeof val !== 'number') {
|
|
||||||
val = svcparam.keyToNumber(val)
|
|
||||||
}
|
|
||||||
buf.writeUInt16BE(val, offset)
|
|
||||||
offset += 2
|
|
||||||
svcparam.encode.bytes += 2
|
|
||||||
}
|
|
||||||
} else if (key === 1) { // alpn
|
|
||||||
let val = param.value
|
|
||||||
if (!Array.isArray(val)) val = [val]
|
|
||||||
// The alpn param is prefixed by its length as a single byte, so the
|
|
||||||
// initialValue to reduce function is the length of the array.
|
|
||||||
let total = val.reduce(function (result, id) {
|
|
||||||
result += id.length
|
|
||||||
return result
|
|
||||||
}, val.length)
|
|
||||||
|
|
||||||
buf.writeUInt16BE(total, offset)
|
|
||||||
offset += 2
|
|
||||||
svcparam.encode.bytes += 2
|
|
||||||
|
|
||||||
for (let id of val) {
|
|
||||||
buf.writeUInt8(id.length, offset)
|
|
||||||
offset += 1
|
|
||||||
svcparam.encode.bytes += 1
|
|
||||||
|
|
||||||
buf.write(id, offset)
|
|
||||||
offset += id.length
|
|
||||||
svcparam.encode.bytes += id.length
|
|
||||||
}
|
|
||||||
} else if (key === 2) { // no-default-alpn
|
|
||||||
buf.writeUInt16BE(0, offset)
|
|
||||||
offset += 2
|
|
||||||
svcparam.encode.bytes += 2
|
|
||||||
} else if (key === 3) { // port
|
|
||||||
buf.writeUInt16BE(2, offset)
|
|
||||||
offset += 2
|
|
||||||
svcparam.encode.bytes += 2
|
|
||||||
buf.writeUInt16BE(param.value || 0, offset)
|
|
||||||
offset += 2
|
|
||||||
svcparam.encode.bytes += 2
|
|
||||||
} else if (key === 4) { // ipv4hint
|
|
||||||
let val = param.value
|
|
||||||
if (!Array.isArray(val)) val = [val]
|
|
||||||
buf.writeUInt16BE(val.length * 4, offset)
|
|
||||||
offset += 2
|
|
||||||
svcparam.encode.bytes += 2
|
|
||||||
|
|
||||||
for (let host of val) {
|
|
||||||
ip.v4.encode(host, buf, offset)
|
|
||||||
offset += 4
|
|
||||||
svcparam.encode.bytes += 4
|
|
||||||
}
|
|
||||||
} else if (key === 5) { // echconfig
|
|
||||||
if (svcparam.ech) {
|
|
||||||
buf.writeUInt16BE(svcparam.ech.length, offset)
|
|
||||||
offset += 2
|
|
||||||
svcparam.encode.bytes += 2
|
|
||||||
for (let i = 0; i < svcparam.ech.length; i++) {
|
|
||||||
buf.writeUInt8(svcparam.ech[i], offset)
|
|
||||||
offset++
|
|
||||||
}
|
|
||||||
svcparam.encode.bytes += svcparam.ech.length
|
|
||||||
} else {
|
|
||||||
buf.writeUInt16BE(param.value.length, offset)
|
|
||||||
offset += 2
|
|
||||||
svcparam.encode.bytes += 2
|
|
||||||
buf.write(param.value, offset)
|
|
||||||
offset += param.value.length
|
|
||||||
svcparam.encode.bytes += param.value.length
|
|
||||||
}
|
|
||||||
} else if (key === 6) { // ipv6hint
|
|
||||||
let val = param.value
|
|
||||||
if (!Array.isArray(val)) val = [val]
|
|
||||||
buf.writeUInt16BE(val.length * 16, offset)
|
|
||||||
offset += 2
|
|
||||||
svcparam.encode.bytes += 2
|
|
||||||
|
|
||||||
for (let host of val) {
|
|
||||||
ip.v6.encode(host, buf, offset)
|
|
||||||
offset += 16
|
|
||||||
svcparam.encode.bytes += 16
|
|
||||||
}
|
|
||||||
} else if (key === 7) { // dohpath
|
|
||||||
buf.writeUInt16BE(param.value.length, offset)
|
|
||||||
offset += 2
|
|
||||||
svcparam.encode.bytes += 2
|
|
||||||
buf.write(param.value, offset)
|
|
||||||
offset += param.value.length
|
|
||||||
svcparam.encode.bytes += param.value.length
|
|
||||||
} else if (key === 32769) { // odoh
|
|
||||||
if (svcparam.odoh) {
|
|
||||||
buf.writeUInt16BE(svcparam.odoh.length, offset)
|
|
||||||
offset += 2
|
|
||||||
svcparam.encode.bytes += 2
|
|
||||||
for (let i = 0; i < svcparam.odoh.length; i++) {
|
|
||||||
buf.writeUInt8(svcparam.odoh[i], offset)
|
|
||||||
offset++
|
|
||||||
}
|
|
||||||
svcparam.encode.bytes += svcparam.odoh.length
|
|
||||||
svcparam.odoh = null
|
|
||||||
} else {
|
|
||||||
buf.writeUInt16BE(param.value.length, offset)
|
|
||||||
offset += 2
|
|
||||||
svcparam.encode.bytes += 2
|
|
||||||
buf.write(param.value, offset)
|
|
||||||
offset += param.value.length
|
|
||||||
svcparam.encode.bytes += param.value.length
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// XXX: why would we ever succeed here, why not fail with an exception to let the user know?
|
|
||||||
// Unknown option
|
|
||||||
buf.writeUInt16BE(0, offset) // 0 length since we don't know how to encode
|
|
||||||
offset += 2
|
|
||||||
svcparam.encode.bytes += 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
svcparam.encode.bytes = 0
|
|
||||||
|
|
||||||
svcparam.decode = function (buf, offset) {
|
|
||||||
if (!offset) offset = 0
|
|
||||||
let param = {}
|
|
||||||
let id = buf.readUInt16BE(offset)
|
|
||||||
param.key = svcparam.numberToKeyName(id)
|
|
||||||
offset += 2
|
|
||||||
svcparam.decode.bytes = 2
|
|
||||||
|
|
||||||
let len = buf.readUInt16BE(offset)
|
|
||||||
offset += 2
|
|
||||||
svcparam.decode.bytes += 2
|
|
||||||
|
|
||||||
// decode the svcparam value
|
|
||||||
switch (param.key.toLowerCase()) {
|
|
||||||
case 'mandatory':
|
|
||||||
{
|
|
||||||
let mp = []
|
|
||||||
let paramsoff = offset
|
|
||||||
let rem = len
|
|
||||||
while (rem >= 2) {
|
|
||||||
let paramtype = buf.readUInt16BE(paramsoff)
|
|
||||||
mp.push(svcparam.numberToKeyName(paramtype))
|
|
||||||
paramsoff += 2
|
|
||||||
rem -= 2
|
|
||||||
}
|
|
||||||
param.value = mp
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'alpn':
|
|
||||||
{
|
|
||||||
let names = []
|
|
||||||
let nameoff = offset
|
|
||||||
let rem = len
|
|
||||||
while (rem >= 2) {
|
|
||||||
const namelen = buf.readUInt8(nameoff)
|
|
||||||
nameoff++
|
|
||||||
rem--
|
|
||||||
if (namelen > rem) {
|
|
||||||
throw new Error(`Invalid SVCB param ALPN length: ${namelen}. Not enough space left in buffer`)
|
|
||||||
}
|
|
||||||
names.push(buf.toString('utf-8', nameoff, nameoff + namelen))
|
|
||||||
nameoff += namelen
|
|
||||||
rem -= namelen
|
|
||||||
}
|
|
||||||
param.value = names
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'no-default-alpn':
|
|
||||||
// data should be empty
|
|
||||||
param.value = 0
|
|
||||||
break
|
|
||||||
case 'port':
|
|
||||||
param.value = buf.readUInt16BE(offset)
|
|
||||||
break
|
|
||||||
case 'ipv4hint':
|
|
||||||
{
|
|
||||||
let ips = []
|
|
||||||
let ipoff = offset
|
|
||||||
let rem = len
|
|
||||||
while (rem >= 4) {
|
|
||||||
ips.push(ip.v4.decode(buf, ipoff))
|
|
||||||
ipoff += 4
|
|
||||||
rem -= 4
|
|
||||||
}
|
|
||||||
param.value = ips
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'ipv6hint':
|
|
||||||
{
|
|
||||||
let ips = []
|
|
||||||
let ipoff = offset
|
|
||||||
let rem = len
|
|
||||||
while (rem >= 16) {
|
|
||||||
ips.push(ip.v6.decode(buf, ipoff))
|
|
||||||
ipoff += 16
|
|
||||||
rem -= 16
|
|
||||||
}
|
|
||||||
param.value = ips
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'dohpath':
|
|
||||||
default:
|
|
||||||
param.value = buf.toString('utf-8', offset, offset + len)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += len
|
|
||||||
svcparam.decode.bytes += len
|
|
||||||
|
|
||||||
return param
|
|
||||||
}
|
|
||||||
|
|
||||||
svcparam.decode.bytes = 0
|
|
||||||
|
|
||||||
svcparam.encodingLength = function (param) {
|
|
||||||
// 2 bytes for type, 2 bytes for length, what's left for the value
|
|
||||||
|
|
||||||
switch (param.key) {
|
|
||||||
case 'mandatory' : return 4 + 2 * (Array.isArray(param.value) ? param.value.length : 1)
|
|
||||||
case 'alpn' : {
|
|
||||||
let val = param.value
|
|
||||||
if (!Array.isArray(val)) val = [val]
|
|
||||||
let total = val.reduce(function (result, id) {
|
|
||||||
result += id.length
|
|
||||||
return result
|
|
||||||
}, val.length)
|
|
||||||
return 4 + total
|
|
||||||
}
|
|
||||||
case 'no-default-alpn' : return 4
|
|
||||||
case 'port' : return 4 + 2
|
|
||||||
case 'ipv4hint' : return 4 + 4 * (Array.isArray(param.value) ? param.value.length : 1)
|
|
||||||
case 'echconfig' : {
|
|
||||||
if (param.needBase64Decode) {
|
|
||||||
svcparam.ech = Buffer.from(param.value, 'base64')
|
|
||||||
return 4 + svcparam.ech.length
|
|
||||||
}
|
|
||||||
return 4 + param.value.length
|
|
||||||
}
|
|
||||||
case 'ipv6hint' : return 4 + 16 * (Array.isArray(param.value) ? param.value.length : 1)
|
|
||||||
case 'odoh' : {
|
|
||||||
if (param.needBase64Decode) {
|
|
||||||
svcparam.odoh = Buffer.from(param.value, 'base64')
|
|
||||||
return 4 + svcparam.odoh.length
|
|
||||||
}
|
|
||||||
return 4 + param.value.length
|
|
||||||
}
|
|
||||||
case 'dohpath': {
|
|
||||||
return 4 + param.value.length
|
|
||||||
}
|
|
||||||
case 'key65535' : return 4
|
|
||||||
default: return 4 // unknown option
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const rhttpssvc = exports.httpssvc = {}
|
|
||||||
|
|
||||||
rhttpssvc.encode = function (data, buf, offset) {
|
|
||||||
if (!buf) buf = Buffer.allocUnsafe(rhttpssvc.encodingLength(data))
|
|
||||||
if (!offset) offset = 0
|
|
||||||
|
|
||||||
buf.writeUInt16BE(rhttpssvc.encodingLength(data) - 2, offset)
|
|
||||||
offset += 2
|
|
||||||
|
|
||||||
buf.writeUInt16BE(data.priority || 0, offset)
|
|
||||||
rhttpssvc.encode.bytes = 4
|
|
||||||
offset += 2
|
|
||||||
name.encode(data.name, buf, offset)
|
|
||||||
rhttpssvc.encode.bytes += name.encode.bytes
|
|
||||||
offset += name.encode.bytes
|
|
||||||
|
|
||||||
if (!data.values) data.values = {}
|
|
||||||
for (const key in data.values) {
|
|
||||||
let val = { key, value: data.values[key] }
|
|
||||||
console.log(`val: ${val}`)
|
|
||||||
svcparam.encode(val, buf, offset)
|
|
||||||
offset += svcparam.encode.bytes
|
|
||||||
rhttpssvc.encode.bytes += svcparam.encode.bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
rhttpssvc.encode.bytes = 0
|
|
||||||
|
|
||||||
rhttpssvc.decode = function (buf, offset) {
|
|
||||||
if (!offset) offset = 0
|
|
||||||
let rdlen = buf.readUInt16BE(offset)
|
|
||||||
offset += 2
|
|
||||||
let record = {}
|
|
||||||
record.priority = buf.readUInt16BE(offset)
|
|
||||||
offset += 2
|
|
||||||
rhttpssvc.decode.bytes = 4
|
|
||||||
record.name = name.decode(buf, offset)
|
|
||||||
offset += name.decode.bytes
|
|
||||||
rhttpssvc.decode.bytes += name.decode.bytes
|
|
||||||
|
|
||||||
while (rdlen > rhttpssvc.decode.bytes - 2) {
|
|
||||||
let rec1 = svcparam.decode(buf, offset)
|
|
||||||
offset += svcparam.decode.bytes
|
|
||||||
rhttpssvc.decode.bytes += svcparam.decode.bytes
|
|
||||||
if (!record.values) {
|
|
||||||
record.values = {}
|
|
||||||
}
|
|
||||||
record.values[rec1.key] = rec1.value
|
|
||||||
}
|
|
||||||
|
|
||||||
return record
|
|
||||||
}
|
|
||||||
|
|
||||||
rhttpssvc.decode.bytes = 0
|
|
||||||
|
|
||||||
rhttpssvc.encodingLength = function (data) {
|
|
||||||
let len =
|
|
||||||
2 + // rdlen
|
|
||||||
2 + // priority
|
|
||||||
name.encodingLength(data.name)
|
|
||||||
if (!data.values) data.values = {}
|
|
||||||
for (const key in data.values) {
|
|
||||||
len += svcparam.encodingLength({ key, value: data.values[key] })
|
|
||||||
}
|
|
||||||
return len
|
|
||||||
}
|
|
||||||
|
|
||||||
const rsvcb = rhttpssvc // SCVB is the same parser as HTTPS
|
|
||||||
exports.svcb = rsvcb
|
|
||||||
|
|
||||||
const renc = exports.record = function (type) {
|
const renc = exports.record = function (type) {
|
||||||
switch (type.toUpperCase()) {
|
switch (type.toUpperCase()) {
|
||||||
case 'A': return ra
|
case 'A': return ra
|
||||||
@ -1882,8 +1499,6 @@ const renc = exports.record = function (type) {
|
|||||||
case 'DS': return rds
|
case 'DS': return rds
|
||||||
case 'NAPTR': return rnaptr
|
case 'NAPTR': return rnaptr
|
||||||
case 'TLSA': return rtlsa
|
case 'TLSA': return rtlsa
|
||||||
case 'SVCB': return rsvcb
|
|
||||||
case 'HTTPS': return rhttpssvc
|
|
||||||
}
|
}
|
||||||
return runknown
|
return runknown
|
||||||
}
|
}
|
||||||
@ -2006,8 +1621,8 @@ question.decode = function (buf, offset) {
|
|||||||
q.type = types.toString(buf.readUInt16BE(offset))
|
q.type = types.toString(buf.readUInt16BE(offset))
|
||||||
offset += 2
|
offset += 2
|
||||||
|
|
||||||
q.qu_bit = (buf.readUInt16BE(offset) & QU_MASK) !== 0
|
q.qu_bit = (buf.readUInt16BE(offset) & QU_MASK) != 0;
|
||||||
q.class = q.qu_bit ? classes.toString(buf.readUInt16BE(offset) - QU_MASK) : classes.toString(buf.readUInt16BE(offset))
|
q.class = q.qu_bit ? classes.toString(buf.readUInt16BE(offset) - QU_MASK) : classes.toString(buf.readUInt16BE(offset));
|
||||||
offset += 2
|
offset += 2
|
||||||
|
|
||||||
question.decode.bytes = offset - oldOffset
|
question.decode.bytes = offset - oldOffset
|
||||||
|
|||||||
560
test.js
560
test.js
@ -6,10 +6,6 @@ const rcodes = require('./rcodes')
|
|||||||
const opcodes = require('./opcodes')
|
const opcodes = require('./opcodes')
|
||||||
const optioncodes = require('./optioncodes')
|
const optioncodes = require('./optioncodes')
|
||||||
|
|
||||||
const ip = require('@leichtgewicht/ip-codec')
|
|
||||||
|
|
||||||
const hexdump = require('./hexdump')
|
|
||||||
|
|
||||||
tape('unknown', function (t) {
|
tape('unknown', function (t) {
|
||||||
testEncoder(t, packet.unknown, Buffer.from('hello world'))
|
testEncoder(t, packet.unknown, Buffer.from('hello world'))
|
||||||
t.end()
|
t.end()
|
||||||
@ -168,34 +164,6 @@ tape('query', function (t) {
|
|||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
|
|
||||||
testEncoder(t, packet, {
|
|
||||||
type: 'query',
|
|
||||||
questions: [{
|
|
||||||
type: 'A',
|
|
||||||
class: 'IN',
|
|
||||||
name: 'hello.a.com',
|
|
||||||
qu_bit: false
|
|
||||||
}, {
|
|
||||||
type: 'SRV',
|
|
||||||
name: 'hello.srv.com',
|
|
||||||
qu_bit: false
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
|
|
||||||
testEncoder(t, packet, {
|
|
||||||
type: 'query',
|
|
||||||
questions: [{
|
|
||||||
type: 'A',
|
|
||||||
class: 'IN',
|
|
||||||
name: 'hello.a.com',
|
|
||||||
qu_bit: true
|
|
||||||
}, {
|
|
||||||
type: 'SRV',
|
|
||||||
name: 'hello.srv.com',
|
|
||||||
qu_bit: true
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
|
|
||||||
t.end()
|
t.end()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -647,534 +615,6 @@ tape('tlsa', function (t) {
|
|||||||
t.end()
|
t.end()
|
||||||
})
|
})
|
||||||
|
|
||||||
const unhexlify = (hex) => {
|
|
||||||
return Buffer.from(hex.match(/[\da-f]{2}/gi).map(function (h) { return parseInt(h, 16) }))
|
|
||||||
}
|
|
||||||
|
|
||||||
// <HTTPS SVCB test cases>
|
|
||||||
const debugHttps = false
|
|
||||||
|
|
||||||
const testScvbDecodeEncode = (t, testname, packetbuf, expected, skipEncode = false, skipMemcmpBufs = false) => {
|
|
||||||
const decoded = packet.svcb.decode(packetbuf, 0)
|
|
||||||
if (debugHttps) {
|
|
||||||
console.log(`${testname}: decode:`)
|
|
||||||
console.log(JSON.stringify(decoded, null, 2))
|
|
||||||
}
|
|
||||||
t.ok(compare(t, decoded, expected), 'svcb ' + testname + ' decode')
|
|
||||||
const encoded = packet.svcb.encode(expected)
|
|
||||||
if (!skipEncode) {
|
|
||||||
if (debugHttps) {
|
|
||||||
console.log(`${testname}: encode:`)
|
|
||||||
hexdump(encoded)
|
|
||||||
}
|
|
||||||
if (!skipMemcmpBufs) {
|
|
||||||
t.ok(compare(t, packetbuf, encoded), 'svcb ' + testname + ' encode memcmp')
|
|
||||||
}
|
|
||||||
// now decode the encoded buffer and check for sameness
|
|
||||||
const recoded = packet.svcb.decode(encoded, 0)
|
|
||||||
if (debugHttps) {
|
|
||||||
console.log(`${testname}: recode`)
|
|
||||||
console.log(JSON.stringify(decoded, null, 2))
|
|
||||||
}
|
|
||||||
t.ok(compare(t, recoded, expected), 'svcb ' + testname + ' recode')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const testHttpsDecodeEncode = (t, testname, packetbuf, expected, skipEncode = false, skipMemcmpBufs = false) => {
|
|
||||||
const decoded = packet.httpssvc.decode(packetbuf, 0)
|
|
||||||
if (debugHttps) {
|
|
||||||
console.log(`${testname}: decode:`)
|
|
||||||
console.log(JSON.stringify(decoded, null, 2))
|
|
||||||
}
|
|
||||||
t.ok(compare(t, decoded, expected), 'https ' + testname + ' decode')
|
|
||||||
const encoded = packet.httpssvc.encode(expected)
|
|
||||||
if (!skipEncode) {
|
|
||||||
if (debugHttps) {
|
|
||||||
console.log(`${testname}: encode:`)
|
|
||||||
hexdump(encoded)
|
|
||||||
}
|
|
||||||
if (!skipMemcmpBufs) {
|
|
||||||
t.ok(compare(t, packetbuf, encoded), 'https ' + testname + ' encode memcmp')
|
|
||||||
}
|
|
||||||
// now decode the encoded buffer and check for sameness
|
|
||||||
const recoded = packet.httpssvc.decode(encoded, 0)
|
|
||||||
if (debugHttps) {
|
|
||||||
console.log(`${testname}: recode`)
|
|
||||||
console.log(JSON.stringify(decoded, null, 2))
|
|
||||||
}
|
|
||||||
t.ok(compare(t, recoded, expected), 'https ' + testname + ' recode')
|
|
||||||
}
|
|
||||||
return encoded
|
|
||||||
}
|
|
||||||
|
|
||||||
const testHttpsSvcbDecodeEncode = (t, testname, packetbuf, expected, skipEncode = false, skipMemcmpBufs = false) => {
|
|
||||||
testScvbDecodeEncode(t, testname, packetbuf, expected, skipEncode, skipMemcmpBufs)
|
|
||||||
return testHttpsDecodeEncode(t, testname, packetbuf, expected, skipEncode, skipMemcmpBufs)
|
|
||||||
}
|
|
||||||
|
|
||||||
tape('https svcb', function (t) {
|
|
||||||
// for the test vectors see:
|
|
||||||
// https://datatracker.ietf.org/doc/rfc9460/
|
|
||||||
// https://github.com/MikeBishop/dns-alt-svc/blob/main/draft-ietf-dnsop-svcb-https.md
|
|
||||||
|
|
||||||
testEncoder(t, packet.svcb, {
|
|
||||||
priority: 16,
|
|
||||||
name: 'foo.example.org',
|
|
||||||
values: {
|
|
||||||
mandatory: [
|
|
||||||
'alpn',
|
|
||||||
'ipv4hint'
|
|
||||||
],
|
|
||||||
alpn: [
|
|
||||||
'h2',
|
|
||||||
'h3-19'
|
|
||||||
],
|
|
||||||
ipv4hint: [
|
|
||||||
'192.0.2.1'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
testEncoder(t, packet.httpssvc, {
|
|
||||||
priority: 16,
|
|
||||||
name: 'foo.example.org',
|
|
||||||
values: {
|
|
||||||
mandatory: [
|
|
||||||
'alpn',
|
|
||||||
'ipv4hint'
|
|
||||||
],
|
|
||||||
alpn: [
|
|
||||||
'h2',
|
|
||||||
'h3-19'
|
|
||||||
],
|
|
||||||
ipv4hint: [
|
|
||||||
'192.0.2.1'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// https AliasMode
|
|
||||||
testHttpsSvcbDecodeEncode(t, 'rfc9460 case1 (AliasMode)',
|
|
||||||
unhexlify(
|
|
||||||
'00 13' + // rdata len
|
|
||||||
'00 00' + // priority
|
|
||||||
'03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00' // target
|
|
||||||
),
|
|
||||||
{
|
|
||||||
priority: 0,
|
|
||||||
name: 'foo.example.com'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// https target name is "."
|
|
||||||
testHttpsSvcbDecodeEncode(t, 'rfc9460 case2 (target name ".")',
|
|
||||||
unhexlify(
|
|
||||||
'00 03' + // rdata len
|
|
||||||
'00 01' + // priority
|
|
||||||
'00' // target (root label)
|
|
||||||
),
|
|
||||||
{
|
|
||||||
priority: 1,
|
|
||||||
name: '.'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// https port
|
|
||||||
testHttpsSvcbDecodeEncode(t, 'rfc9460 case3 (port)',
|
|
||||||
unhexlify(
|
|
||||||
'00 19' + // rdata len
|
|
||||||
'00 10' + // priority
|
|
||||||
'03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00' + // target
|
|
||||||
'00 03' + // key 3
|
|
||||||
'00 02' + // length 2
|
|
||||||
'00 35' // value - target (root label)
|
|
||||||
),
|
|
||||||
{
|
|
||||||
priority: 16,
|
|
||||||
name: 'foo.example.com',
|
|
||||||
values: {
|
|
||||||
port: 53
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// https generic key and value
|
|
||||||
testHttpsSvcbDecodeEncode(t, 'rfc9460 case4 (generic key,val)',
|
|
||||||
unhexlify(
|
|
||||||
'00 1c' + // rdata len
|
|
||||||
'00 01' + // priority
|
|
||||||
'03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00' + // target
|
|
||||||
'02 9b' + // key 667
|
|
||||||
'00 05' + // length 5
|
|
||||||
'68 65 6c 6c 6f' // value
|
|
||||||
),
|
|
||||||
{
|
|
||||||
priority: 1,
|
|
||||||
name: 'foo.example.com',
|
|
||||||
values: {
|
|
||||||
key667: 'hello'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
true // skipEncode, we cannot encode an unknown key
|
|
||||||
)
|
|
||||||
|
|
||||||
// https generic key and value with decimal escape
|
|
||||||
testHttpsSvcbDecodeEncode(t, 'rfc9460 case5 (generic key,val with escape)',
|
|
||||||
unhexlify(
|
|
||||||
'00 20' + // rdata len
|
|
||||||
'00 01' + // priority
|
|
||||||
'03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00' + // target
|
|
||||||
'02 9b' + // key 667
|
|
||||||
'00 09' + // length 9
|
|
||||||
'68 65 6c 6c 6f d2 71 6f 6f' // value
|
|
||||||
),
|
|
||||||
{
|
|
||||||
priority: 1,
|
|
||||||
name: 'foo.example.com',
|
|
||||||
values: {
|
|
||||||
key667: unhexlify('68 65 6c 6c 6f d2 71 6f 6f').toString('utf-8')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
true // skipEncode, we cannot encode an unknown key
|
|
||||||
)
|
|
||||||
|
|
||||||
// https two quoted ipv6 hints
|
|
||||||
testHttpsSvcbDecodeEncode(t, 'rfc9460 case6 (ipv6hint)',
|
|
||||||
unhexlify(
|
|
||||||
'00 37' + // rdata len
|
|
||||||
'00 01' + // priority
|
|
||||||
'03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00' + // target
|
|
||||||
'00 06' + // key 6
|
|
||||||
'00 20' + // length 32
|
|
||||||
'20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 01' + // first address
|
|
||||||
'20 01 0d b8 00 00 00 00 00 00 00 00 00 53 00 01' // second address
|
|
||||||
),
|
|
||||||
{
|
|
||||||
priority: 1,
|
|
||||||
name: 'foo.example.com',
|
|
||||||
values: {
|
|
||||||
ipv6hint: [
|
|
||||||
'2001:db8::1',
|
|
||||||
'2001:db8::53:1'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// https ipv6 hint using embedded ipv4 syntax [2001:db8:122:344::192.0.2.33]
|
|
||||||
testHttpsSvcbDecodeEncode(t, 'rfc9460 case7 (ipv6hint v4 syntax)',
|
|
||||||
unhexlify(
|
|
||||||
'00 23' + // rdata len
|
|
||||||
'00 01' + // priority
|
|
||||||
'07 65 78 61 6d 70 6c 65 03 63 6f 6d 00' + // target
|
|
||||||
'00 06' + // key 6
|
|
||||||
'00 10' + // length 16
|
|
||||||
'20 01 0d b8 01 22 03 44 00 00 00 00 c0 00 02 21' // address
|
|
||||||
),
|
|
||||||
{
|
|
||||||
priority: 1,
|
|
||||||
name: 'example.com',
|
|
||||||
values: {
|
|
||||||
ipv6hint: [ ip.v6.decode(ip.v6.encode('2001:db8:122:344::192.0.2.33')) ]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// case 8
|
|
||||||
// https 16 foo.example.org. (
|
|
||||||
// alpn=h2,h3-19 mandatory=ipv4hint,alpn
|
|
||||||
// ipv4hint=192.0.2.1
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// note: this may not encode to the same buffer due to internal js
|
|
||||||
// ordering of the `values` object storing the params
|
|
||||||
testHttpsSvcbDecodeEncode(t, 'rfc9460 case8 (alpn,mandatory,ipv4hint)',
|
|
||||||
unhexlify(
|
|
||||||
'00 30' + // rdata len
|
|
||||||
'00 10' + // priority
|
|
||||||
'03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 6f 72 67 00' + // target
|
|
||||||
'00 00' + // key 0
|
|
||||||
'00 04' + // param length 4
|
|
||||||
'00 01' + // value: key 1
|
|
||||||
'00 04' + // value: key 4
|
|
||||||
'00 01' + // key 1
|
|
||||||
'00 09' + // param length 9
|
|
||||||
'02' + // alpn length 2
|
|
||||||
'68 32' + // alpn value
|
|
||||||
'05' + // alpn length 5
|
|
||||||
'68 33 2d 31 39' + // alpn value
|
|
||||||
'00 04' + // key 4
|
|
||||||
'00 04' + // param length 4
|
|
||||||
'c0 00 02 01' // param value
|
|
||||||
),
|
|
||||||
{
|
|
||||||
priority: 16,
|
|
||||||
name: 'foo.example.org',
|
|
||||||
values: {
|
|
||||||
mandatory: [
|
|
||||||
'alpn',
|
|
||||||
'ipv4hint'
|
|
||||||
],
|
|
||||||
alpn: [
|
|
||||||
'h2',
|
|
||||||
'h3-19'
|
|
||||||
],
|
|
||||||
ipv4hint: [
|
|
||||||
'192.0.2.1'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false, // skipEncode: false
|
|
||||||
true // skipMemcmpBufs: true, do not directly memcmp the resulting bufs, see comment above
|
|
||||||
)
|
|
||||||
|
|
||||||
t.end()
|
|
||||||
})
|
|
||||||
|
|
||||||
tape('cloudflare real world svcb/https', (t) => {
|
|
||||||
const httpsBuf = unhexlify(
|
|
||||||
'ef 23 81 80 00 01 00 01 00 00 00 01 09 63 6f 6d' +
|
|
||||||
'6d 75 6e 69 74 79 0a 63 6c 6f 75 64 66 6c 61 72' +
|
|
||||||
'65 03 63 6f 6d 00 00 41 00 01 09 63 6f 6d 6d 75' +
|
|
||||||
'6e 69 74 79 0a 63 6c 6f 75 64 66 6c 61 72 65 03' +
|
|
||||||
'63 6f 6d 00 00 41 00 01 00 00 00 3c 00 3d 00 01' +
|
|
||||||
'00 00 01 00 06 02 68 33 02 68 32 00 04 00 08 68' +
|
|
||||||
'12 02 43 68 12 03 43 00 06 00 20 26 06 47 00 00' +
|
|
||||||
'00 00 00 00 00 00 00 68 12 02 43 26 06 47 00 00' +
|
|
||||||
'00 00 00 00 00 00 00 68 12 03 43 00 00 29 02 00' +
|
|
||||||
'00 00 00 00 00 00'
|
|
||||||
)
|
|
||||||
const svcbBuf = unhexlify(
|
|
||||||
'ef 23 81 80 00 01 00 01 00 00 00 01 09 63 6f 6d' +
|
|
||||||
'6d 75 6e 69 74 79 0a 63 6c 6f 75 64 66 6c 61 72' +
|
|
||||||
'65 03 63 6f 6d 00 00 40 00 01 09 63 6f 6d 6d 75' +
|
|
||||||
'6e 69 74 79 0a 63 6c 6f 75 64 66 6c 61 72 65 03' +
|
|
||||||
'63 6f 6d 00 00 40 00 01 00 00 00 3c 00 3d 00 01' +
|
|
||||||
'00 00 01 00 06 02 68 33 02 68 32 00 04 00 08 68' +
|
|
||||||
'12 02 43 68 12 03 43 00 06 00 20 26 06 47 00 00' +
|
|
||||||
'00 00 00 00 00 00 00 68 12 02 43 26 06 47 00 00' +
|
|
||||||
'00 00 00 00 00 00 00 68 12 03 43 00 00 29 02 00' +
|
|
||||||
'00 00 00 00 00 00'
|
|
||||||
)
|
|
||||||
|
|
||||||
let expected = {
|
|
||||||
id: 61219,
|
|
||||||
type: 'response',
|
|
||||||
flags: 384,
|
|
||||||
flag_qr: true,
|
|
||||||
opcode: 'QUERY',
|
|
||||||
flag_aa: false,
|
|
||||||
flag_tc: false,
|
|
||||||
flag_rd: true,
|
|
||||||
flag_ra: true,
|
|
||||||
flag_z: false,
|
|
||||||
flag_ad: false,
|
|
||||||
flag_cd: false,
|
|
||||||
rcode: 'NOERROR',
|
|
||||||
questions: [
|
|
||||||
{
|
|
||||||
name: 'community.cloudflare.com',
|
|
||||||
type: 'HTTPS',
|
|
||||||
class: 'IN'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
answers: [
|
|
||||||
{
|
|
||||||
name: 'community.cloudflare.com',
|
|
||||||
type: 'HTTPS',
|
|
||||||
ttl: 60,
|
|
||||||
class: 'IN',
|
|
||||||
flush: false,
|
|
||||||
data: {
|
|
||||||
priority: 1,
|
|
||||||
name: '.',
|
|
||||||
values: {
|
|
||||||
alpn: [
|
|
||||||
'h3',
|
|
||||||
'h2'
|
|
||||||
],
|
|
||||||
ipv4hint: [
|
|
||||||
'104.18.2.67',
|
|
||||||
'104.18.3.67'
|
|
||||||
],
|
|
||||||
ipv6hint: [
|
|
||||||
'2606:4700::6812:243',
|
|
||||||
'2606:4700::6812:343'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
authorities: [],
|
|
||||||
additionals: [
|
|
||||||
{
|
|
||||||
name: '.',
|
|
||||||
type: 'OPT',
|
|
||||||
udpPayloadSize: 512,
|
|
||||||
extendedRcode: 0,
|
|
||||||
ednsVersion: 0,
|
|
||||||
flags: 0,
|
|
||||||
flag_do: false,
|
|
||||||
options: []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
const decodedHttps = packet.decode(httpsBuf)
|
|
||||||
t.ok(decodedHttps, 'cloudflare real world https decoded')
|
|
||||||
if (debugHttps) {
|
|
||||||
console.log(`cloudflare real world: decodedHttps:`)
|
|
||||||
console.log(JSON.stringify(decodedHttps, null, 2))
|
|
||||||
}
|
|
||||||
t.ok(compare(t, decodedHttps, expected), 'cloudflare real world https compare')
|
|
||||||
|
|
||||||
const decodedSvcb = packet.decode(svcbBuf)
|
|
||||||
t.ok(decodedSvcb, 'cloudflare real world svcb decoded')
|
|
||||||
if (debugHttps) {
|
|
||||||
console.log(`cloudflare real world: decodedSvcb:`)
|
|
||||||
console.log(JSON.stringify(decodedSvcb, null, 2))
|
|
||||||
}
|
|
||||||
expected.questions[0].type = expected.answers[0].type = 'SVCB'
|
|
||||||
t.ok(compare(t, decodedSvcb, expected), 'cloudflare real world svcb compare')
|
|
||||||
|
|
||||||
t.end()
|
|
||||||
})
|
|
||||||
|
|
||||||
tape('google resolver SVCB real world', function (t) {
|
|
||||||
const svcbBuf = unhexlify(
|
|
||||||
'd0 90 85 80 00 01' +
|
|
||||||
'00 02 00 00 00 04 04 5f 64 6e 73 08 72 65 73 6f' +
|
|
||||||
'6c 76 65 72 04 61 72 70 61 00 00 40 00 01 c0 0c' +
|
|
||||||
'00 40 00 01 00 01 51 80 00 16 00 01 03 64 6e 73' +
|
|
||||||
'06 67 6f 6f 67 6c 65 00 00 01 00 04 03 64 6f 74' +
|
|
||||||
'c0 0c 00 40 00 01 00 01 51 80 00 2c 00 02 03 64' +
|
|
||||||
'6e 73 06 67 6f 6f 67 6c 65 00 00 01 00 06 02 68' +
|
|
||||||
'32 02 68 33 00 07 00 10 2f 64 6e 73 2d 71 75 65' +
|
|
||||||
'72 79 7b 3f 64 6e 73 7d 03 64 6e 73 06 67 6f 6f' +
|
|
||||||
'67 6c 65 00 00 01 00 01 00 01 51 80 00 04 08 08' +
|
|
||||||
'08 08 c0 7e 00 01 00 01 00 01 51 80 00 04 08 08' +
|
|
||||||
'04 04 c0 7e 00 1c 00 01 00 01 51 80 00 10 20 01' +
|
|
||||||
'48 60 48 60 00 00 00 00 00 00 00 00 88 88 c0 7e' +
|
|
||||||
'00 1c 00 01 00 01 51 80 00 10 20 01 48 60 48 60' +
|
|
||||||
'00 00 00 00 00 00 00 00 88 44'
|
|
||||||
)
|
|
||||||
|
|
||||||
const expected = {
|
|
||||||
id: 53392,
|
|
||||||
type: 'response',
|
|
||||||
flags: 1408,
|
|
||||||
flag_qr: true,
|
|
||||||
opcode: 'QUERY',
|
|
||||||
flag_aa: true,
|
|
||||||
flag_tc: false,
|
|
||||||
flag_rd: true,
|
|
||||||
flag_ra: true,
|
|
||||||
flag_z: false,
|
|
||||||
flag_ad: false,
|
|
||||||
flag_cd: false,
|
|
||||||
rcode: 'NOERROR',
|
|
||||||
questions: [
|
|
||||||
{
|
|
||||||
name: '_dns.resolver.arpa',
|
|
||||||
type: 'SVCB',
|
|
||||||
class: 'IN'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
answers: [
|
|
||||||
{
|
|
||||||
name: '_dns.resolver.arpa',
|
|
||||||
type: 'SVCB',
|
|
||||||
ttl: 86400,
|
|
||||||
class: 'IN',
|
|
||||||
flush: false,
|
|
||||||
data: {
|
|
||||||
priority: 1,
|
|
||||||
name: 'dns.google',
|
|
||||||
values: {
|
|
||||||
alpn: [
|
|
||||||
'dot'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '_dns.resolver.arpa',
|
|
||||||
type: 'SVCB',
|
|
||||||
ttl: 86400,
|
|
||||||
class: 'IN',
|
|
||||||
flush: false,
|
|
||||||
data: {
|
|
||||||
priority: 2,
|
|
||||||
name: 'dns.google',
|
|
||||||
values: {
|
|
||||||
alpn: [
|
|
||||||
'h2',
|
|
||||||
'h3'
|
|
||||||
],
|
|
||||||
dohpath: '/dns-query{?dns}'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
authorities: [],
|
|
||||||
additionals: [
|
|
||||||
{
|
|
||||||
name: 'dns.google',
|
|
||||||
type: 'A',
|
|
||||||
ttl: 86400,
|
|
||||||
class: 'IN',
|
|
||||||
flush: false,
|
|
||||||
data: '8.8.8.8'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'dns.google',
|
|
||||||
type: 'A',
|
|
||||||
ttl: 86400,
|
|
||||||
class: 'IN',
|
|
||||||
flush: false,
|
|
||||||
data: '8.8.4.4'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'dns.google',
|
|
||||||
type: 'AAAA',
|
|
||||||
ttl: 86400,
|
|
||||||
class: 'IN',
|
|
||||||
flush: false,
|
|
||||||
data: '2001:4860:4860::8888'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'dns.google',
|
|
||||||
type: 'AAAA',
|
|
||||||
ttl: 86400,
|
|
||||||
class: 'IN',
|
|
||||||
flush: false,
|
|
||||||
data: '2001:4860:4860::8844'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
const decodedSvcb = packet.decode(svcbBuf)
|
|
||||||
t.ok(decodedSvcb, 'google real world svcb decoded')
|
|
||||||
if (debugHttps) {
|
|
||||||
console.log(`google real world svcb: decodedSvcb:`)
|
|
||||||
console.log(JSON.stringify(decodedSvcb, null, 2))
|
|
||||||
}
|
|
||||||
t.ok(compare(t, decodedSvcb, expected), 'google real world svcb compare')
|
|
||||||
|
|
||||||
// now test encoding and decoding the individual answer data
|
|
||||||
for (let answer of expected.answers) {
|
|
||||||
const encodedData = packet.svcb.encode(answer.data)
|
|
||||||
const decodedData = packet.svcb.decode(encodedData)
|
|
||||||
t.ok(compare(t, answer.data, decodedData), 'google real world answer recode')
|
|
||||||
}
|
|
||||||
|
|
||||||
t.end()
|
|
||||||
})
|
|
||||||
|
|
||||||
// </HTTPS SVCB test cases>
|
|
||||||
|
|
||||||
tape('unpack', function (t) {
|
tape('unpack', function (t) {
|
||||||
const buf = Buffer.from([
|
const buf = Buffer.from([
|
||||||
0x00, 0x79,
|
0x00, 0x79,
|
||||||
|
|||||||
4
types.js
4
types.js
@ -45,8 +45,6 @@ exports.toString = function (type) {
|
|||||||
case 252: return 'AXFR'
|
case 252: return 'AXFR'
|
||||||
case 251: return 'IXFR'
|
case 251: return 'IXFR'
|
||||||
case 41: return 'OPT'
|
case 41: return 'OPT'
|
||||||
case 64: return 'SVCB'
|
|
||||||
case 65: return 'HTTPS'
|
|
||||||
case 255: return 'ANY'
|
case 255: return 'ANY'
|
||||||
}
|
}
|
||||||
return 'UNKNOWN_' + type
|
return 'UNKNOWN_' + type
|
||||||
@ -97,8 +95,6 @@ exports.toType = function (name) {
|
|||||||
case 'AXFR': return 252
|
case 'AXFR': return 252
|
||||||
case 'IXFR': return 251
|
case 'IXFR': return 251
|
||||||
case 'OPT': return 41
|
case 'OPT': return 41
|
||||||
case 'SVCB': return 64
|
|
||||||
case 'HTTPS': return 65
|
|
||||||
case 'ANY': return 255
|
case 'ANY': return 255
|
||||||
case '*': return 255
|
case '*': return 255
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user