Fixed linting errors

This commit is contained in:
Justin Fisher 2025-07-09 17:11:21 -04:00 committed by LittleChest
parent 74972afbbf
commit 8c70ce60a5
3 changed files with 332 additions and 335 deletions

View File

@ -1,63 +1,63 @@
const wout = (s) => { const wout = (s) => {
process.stdout.write(s); process.stdout.write(s)
} }
const pad_str = (s, len, ch) => { const padStr = (s, len, ch) => {
ch = ch || ' '; ch = ch || ' '
while (s.length < len) { while (s.length < len) {
s = ch + s; s = ch + s
} }
return s return s
} }
const hex_digit = (n, len) => { const hexDigit = (n, len) => {
return pad_str(n.toString(16), len || 2, '0') return padStr(n.toString(16), len || 2, '0')
} }
const printable_ch = (c) => { const printableCh = (c) => {
// [space to '~') // [space to '~')
if (c > 0x20 && c <= 0x7e) { if (c > 0x20 && c <= 0x7e) {
return String.fromCharCode(c); return String.fromCharCode(c)
} else { } else {
return '.'; return '.'
} }
} }
const hexdump = (buf, len) => { const hexdump = (buf, len) => {
len = len || buf.length; len = len || buf.length
const maxline = 16; const maxline = 16
let ascii = new Array(maxline); let ascii = new Array(maxline)
let i; let i
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (i % maxline == 0) { if (i % maxline === 0) {
if (i > 0) { if (i > 0) {
wout(" " + ascii.join("")) wout(' ' + ascii.join(''))
wout("\n"); wout('\n')
} }
wout(hex_digit(i, 4) + ": ") wout(hexDigit(i, 4) + ': ')
} }
// output the hex digit // output the hex digit
wout(hex_digit(buf[i])); wout(hexDigit(buf[i]))
wout(" "); wout(' ')
ascii[i % maxline] = printable_ch(buf[i]); ascii[i % maxline] = printableCh(buf[i])
} }
if (i % maxline != 0) { if (i % maxline !== 0) {
let diff = maxline - (i % maxline); let diff = maxline - (i % maxline)
wout(" ".repeat(diff)) wout(' '.repeat(diff))
} }
wout(" " + ascii.slice(0, (i % maxline)).join("") + "\n") wout(' ' + ascii.slice(0, (i % maxline)).join('') + '\n')
} }
/* /*
let buf = Buffer.alloc(500); let buf = Buffer.alloc(500)
for (let i = 0; i < buf.length; i++) { for (let i = 0; i < buf.length; i++) {
buf[i] = i & 0xff; buf[i] = i & 0xff
} }
hexdump(buf) hexdump(buf)
*/ */
module.exports = hexdump; module.exports = hexdump

View File

@ -1475,7 +1475,7 @@ rtlsa.encodingLength = function (cert) {
const svcparam = exports.svcparam = {} const svcparam = exports.svcparam = {}
svcparam.keyToNumber = function(keyName) { svcparam.keyToNumber = function (keyName) {
switch (keyName.toLowerCase()) { switch (keyName.toLowerCase()) {
case 'mandatory': return 0 case 'mandatory': return 0
case 'alpn' : return 1 case 'alpn' : return 1
@ -1495,7 +1495,7 @@ svcparam.keyToNumber = function(keyName) {
return Number.parseInt(keyName.substring(3)) return Number.parseInt(keyName.substring(3))
} }
svcparam.numberToKeyName = function(number) { svcparam.numberToKeyName = function (number) {
switch (number) { switch (number) {
case 0 : return 'mandatory' case 0 : return 'mandatory'
case 1 : return 'alpn' case 1 : return 'alpn'
@ -1511,11 +1511,11 @@ svcparam.numberToKeyName = function(number) {
return `key${number}` return `key${number}`
} }
svcparam.encode = function(param, buf, offset) { svcparam.encode = function (param, buf, offset) {
if (!buf) buf = Buffer.allocUnsafe(svcparam.encodingLength(param)) if (!buf) buf = Buffer.allocUnsafe(svcparam.encodingLength(param))
if (!offset) offset = 0 if (!offset) offset = 0
let key = param.key; let key = param.key
if (typeof param.key !== 'number') { if (typeof param.key !== 'number') {
key = svcparam.keyToNumber(param.key) key = svcparam.keyToNumber(param.key)
} }
@ -1523,10 +1523,10 @@ svcparam.encode = function(param, buf, offset) {
offset += 2 offset += 2
svcparam.encode.bytes = 2 svcparam.encode.bytes = 2
if (key == 0) { // mandatory if (key === 0) { // mandatory
let values = param.value let values = param.value
if (!Array.isArray(values)) values = [values] if (!Array.isArray(values)) values = [values]
buf.writeUInt16BE(values.length*2, offset) buf.writeUInt16BE(values.length * 2, offset)
offset += 2 offset += 2
svcparam.encode.bytes += 2 svcparam.encode.bytes += 2
@ -1538,13 +1538,14 @@ svcparam.encode = function(param, buf, offset) {
offset += 2 offset += 2
svcparam.encode.bytes += 2 svcparam.encode.bytes += 2
} }
} else if (key == 1) { // alpn } else if (key === 1) { // alpn
let val = param.value let val = param.value
if (!Array.isArray(val)) val = [val] if (!Array.isArray(val)) val = [val]
// The alpn param is prefixed by its length as a single byte, so the // The alpn param is prefixed by its length as a single byte, so the
// initialValue to reduce function is the length of the array. // initialValue to reduce function is the length of the array.
let total = val.reduce(function(result, id) { let total = val.reduce(function (result, id) {
return result += id.length result += id.length
return result
}, val.length) }, val.length)
buf.writeUInt16BE(total, offset) buf.writeUInt16BE(total, offset)
@ -1560,22 +1561,22 @@ svcparam.encode = function(param, buf, offset) {
offset += id.length offset += id.length
svcparam.encode.bytes += id.length svcparam.encode.bytes += id.length
} }
} else if (key == 2) { // no-default-alpn } else if (key === 2) { // no-default-alpn
buf.writeUInt16BE(0, offset) buf.writeUInt16BE(0, offset)
offset += 2 offset += 2
svcparam.encode.bytes += 2 svcparam.encode.bytes += 2
} else if (key == 3) { // port } else if (key === 3) { // port
buf.writeUInt16BE(2, offset) buf.writeUInt16BE(2, offset)
offset += 2 offset += 2
svcparam.encode.bytes += 2 svcparam.encode.bytes += 2
buf.writeUInt16BE(param.value || 0, offset) buf.writeUInt16BE(param.value || 0, offset)
offset += 2 offset += 2
svcparam.encode.bytes += 2 svcparam.encode.bytes += 2
} else if (key == 4) { //ipv4hint } else if (key === 4) { // ipv4hint
let val = param.value let val = param.value
if (!Array.isArray(val)) val = [val] if (!Array.isArray(val)) val = [val]
buf.writeUInt16BE(val.length*4, offset) buf.writeUInt16BE(val.length * 4, offset)
offset += 2; offset += 2
svcparam.encode.bytes += 2 svcparam.encode.bytes += 2
for (let host of val) { for (let host of val) {
@ -1583,7 +1584,7 @@ svcparam.encode = function(param, buf, offset) {
offset += 4 offset += 4
svcparam.encode.bytes += 4 svcparam.encode.bytes += 4
} }
} else if (key == 5) { //echconfig } else if (key === 5) { // echconfig
if (svcparam.ech) { if (svcparam.ech) {
buf.writeUInt16BE(svcparam.ech.length, offset) buf.writeUInt16BE(svcparam.ech.length, offset)
offset += 2 offset += 2
@ -1601,10 +1602,10 @@ svcparam.encode = function(param, buf, offset) {
offset += param.value.length offset += param.value.length
svcparam.encode.bytes += param.value.length svcparam.encode.bytes += param.value.length
} }
} else if (key == 6) { //ipv6hint } else if (key === 6) { // ipv6hint
let val = param.value let val = param.value
if (!Array.isArray(val)) val = [val]; if (!Array.isArray(val)) val = [val]
buf.writeUInt16BE(val.length*16, offset) buf.writeUInt16BE(val.length * 16, offset)
offset += 2 offset += 2
svcparam.encode.bytes += 2 svcparam.encode.bytes += 2
@ -1613,14 +1614,14 @@ svcparam.encode = function(param, buf, offset) {
offset += 16 offset += 16
svcparam.encode.bytes += 16 svcparam.encode.bytes += 16
} }
} else if (key == 7) { // dohpath } else if (key === 7) { // dohpath
buf.writeUInt16BE(param.value.length, offset) buf.writeUInt16BE(param.value.length, offset)
offset += 2 offset += 2
svcparam.encode.bytes += 2 svcparam.encode.bytes += 2
buf.write(param.value, offset) buf.write(param.value, offset)
offset += param.value.length offset += param.value.length
svcparam.encode.bytes += param.value.length svcparam.encode.bytes += param.value.length
} else if (key == 32769) { //odoh } else if (key === 32769) { // odoh
if (svcparam.odoh) { if (svcparam.odoh) {
buf.writeUInt16BE(svcparam.odoh.length, offset) buf.writeUInt16BE(svcparam.odoh.length, offset)
offset += 2 offset += 2
@ -1646,10 +1647,9 @@ svcparam.encode = function(param, buf, offset) {
offset += 2 offset += 2
svcparam.encode.bytes += 2 svcparam.encode.bytes += 2
} }
} }
svcparam.encode.bytes = 0; svcparam.encode.bytes = 0
svcparam.decode = function (buf, offset) { svcparam.decode = function (buf, offset) {
if (!offset) offset = 0 if (!offset) offset = 0
@ -1691,7 +1691,7 @@ svcparam.decode = function (buf, offset) {
if (namelen > rem) { if (namelen > rem) {
throw new Error(`Invalid SVCB param ALPN length: ${namelen}. Not enough space left in buffer`) throw new Error(`Invalid SVCB param ALPN length: ${namelen}. Not enough space left in buffer`)
} }
names.push(buf.toString('utf-8', nameoff, nameoff+namelen)) names.push(buf.toString('utf-8', nameoff, nameoff + namelen))
nameoff += namelen nameoff += namelen
rem -= namelen rem -= namelen
} }
@ -1743,18 +1743,19 @@ svcparam.decode = function (buf, offset) {
return param return param
} }
svcparam.decode.bytes = 0; svcparam.decode.bytes = 0
svcparam.encodingLength = function (param) { svcparam.encodingLength = function (param) {
// 2 bytes for type, 2 bytes for length, what's left for the value // 2 bytes for type, 2 bytes for length, what's left for the value
switch (param.key) { switch (param.key) {
case 'mandatory' : return 4 + 2*(Array.isArray(param.value) ? param.value.length : 1) case 'mandatory' : return 4 + 2 * (Array.isArray(param.value) ? param.value.length : 1)
case 'alpn' : { case 'alpn' : {
let val = param.value let val = param.value
if (!Array.isArray(val)) val = [val] if (!Array.isArray(val)) val = [val]
let total = val.reduce(function(result, id) { let total = val.reduce(function (result, id) {
return result += id.length result += id.length
return result
}, val.length) }, val.length)
return 4 + total return 4 + total
} }
@ -1763,7 +1764,7 @@ svcparam.encodingLength = function (param) {
case 'ipv4hint' : return 4 + 4 * (Array.isArray(param.value) ? param.value.length : 1) case 'ipv4hint' : return 4 + 4 * (Array.isArray(param.value) ? param.value.length : 1)
case 'echconfig' : { case 'echconfig' : {
if (param.needBase64Decode) { if (param.needBase64Decode) {
svcparam.ech = Buffer.from(param.value, "base64") svcparam.ech = Buffer.from(param.value, 'base64')
return 4 + svcparam.ech.length return 4 + svcparam.ech.length
} }
return 4 + param.value.length return 4 + param.value.length
@ -1771,7 +1772,7 @@ svcparam.encodingLength = function (param) {
case 'ipv6hint' : return 4 + 16 * (Array.isArray(param.value) ? param.value.length : 1) case 'ipv6hint' : return 4 + 16 * (Array.isArray(param.value) ? param.value.length : 1)
case 'odoh' : { case 'odoh' : {
if (param.needBase64Decode) { if (param.needBase64Decode) {
svcparam.odoh = Buffer.from(param.value, "base64") svcparam.odoh = Buffer.from(param.value, 'base64')
return 4 + svcparam.odoh.length return 4 + svcparam.odoh.length
} }
return 4 + param.value.length return 4 + param.value.length
@ -1786,11 +1787,11 @@ svcparam.encodingLength = function (param) {
const rhttpssvc = exports.httpssvc = {} const rhttpssvc = exports.httpssvc = {}
rhttpssvc.encode = function(data, buf, offset) { rhttpssvc.encode = function (data, buf, offset) {
if (!buf) buf = Buffer.allocUnsafe(rhttpssvc.encodingLength(data)) if (!buf) buf = Buffer.allocUnsafe(rhttpssvc.encodingLength(data))
if (!offset) offset = 0 if (!offset) offset = 0
buf.writeUInt16BE(rhttpssvc.encodingLength(data) - 2 , offset) buf.writeUInt16BE(rhttpssvc.encodingLength(data) - 2, offset)
offset += 2 offset += 2
buf.writeUInt16BE(data.priority || 0, offset) buf.writeUInt16BE(data.priority || 0, offset)
@ -1801,7 +1802,7 @@ rhttpssvc.encode = function(data, buf, offset) {
offset += name.encode.bytes offset += name.encode.bytes
for (const [key, value] of Object.entries(data.values || {})) { for (const [key, value] of Object.entries(data.values || {})) {
let val = {key, value} let val = { key, value }
svcparam.encode(val, buf, offset) svcparam.encode(val, buf, offset)
offset += svcparam.encode.bytes offset += svcparam.encode.bytes
rhttpssvc.encode.bytes += svcparam.encode.bytes rhttpssvc.encode.bytes += svcparam.encode.bytes
@ -1815,7 +1816,6 @@ rhttpssvc.encode.bytes = 0
rhttpssvc.decode = function (buf, offset) { rhttpssvc.decode = function (buf, offset) {
if (!offset) offset = 0 if (!offset) offset = 0
let rdlen = buf.readUInt16BE(offset) let rdlen = buf.readUInt16BE(offset)
let oldOffset = offset
offset += 2 offset += 2
let record = {} let record = {}
record.priority = buf.readUInt16BE(offset) record.priority = buf.readUInt16BE(offset)
@ -1838,7 +1838,7 @@ rhttpssvc.decode = function (buf, offset) {
return record return record
} }
rhttpssvc.decode.bytes = 0; rhttpssvc.decode.bytes = 0
rhttpssvc.encodingLength = function (data) { rhttpssvc.encodingLength = function (data) {
let len = let len =
@ -1846,7 +1846,7 @@ rhttpssvc.encodingLength = function (data) {
2 + // priority 2 + // priority
name.encodingLength(data.name) name.encodingLength(data.name)
for (const [key, value] of Object.entries(data.values || {})) { for (const [key, value] of Object.entries(data.values || {})) {
len += svcparam.encodingLength({key, value}) len += svcparam.encodingLength({ key, value })
} }
return len return len
} }

441
test.js
View File

@ -647,33 +647,32 @@ tape('tlsa', function (t) {
t.end() t.end()
}) })
const unhexlify = (hex) => { const unhexlify = (hex) => {
return Buffer.from(hex.match(/[\da-f]{2}/gi).map(function (h) {return parseInt(h, 16)})) return Buffer.from(hex.match(/[\da-f]{2}/gi).map(function (h) { return parseInt(h, 16) }))
} }
// <HTTPS SVCB test cases> // <HTTPS SVCB test cases>
const debug_https = false const debugHttps = false
const test_scvb_decode_encode = (t, testname, packetbuf, expected, skip_encode=false, skip_memcmp_bufs=false) => { const testScvbDecodeEncode = (t, testname, packetbuf, expected, skipEncode = false, skipMemcmpBufs = false) => {
const decoded = packet.svcb.decode(packetbuf, 0) const decoded = packet.svcb.decode(packetbuf, 0)
if (debug_https) { if (debugHttps) {
console.log(`${testname}: decode:`) console.log(`${testname}: decode:`)
console.log(JSON.stringify(decoded, null, 2)) console.log(JSON.stringify(decoded, null, 2))
} }
t.ok(compare(t, decoded, expected), 'svcb ' + testname + ' decode') t.ok(compare(t, decoded, expected), 'svcb ' + testname + ' decode')
const encoded = packet.svcb.encode(expected) const encoded = packet.svcb.encode(expected)
if (!skip_encode) { if (!skipEncode) {
if (debug_https) { if (debugHttps) {
console.log(`${testname}: encode:`) console.log(`${testname}: encode:`)
hexdump(encoded) hexdump(encoded)
} }
if (!skip_memcmp_bufs) { if (!skipMemcmpBufs) {
t.ok(compare(t, packetbuf, encoded), 'svcb ' + testname + ' encode memcmp') t.ok(compare(t, packetbuf, encoded), 'svcb ' + testname + ' encode memcmp')
} }
// now decode the encoded buffer and check for sameness // now decode the encoded buffer and check for sameness
const recoded = packet.svcb.decode(encoded, 0) const recoded = packet.svcb.decode(encoded, 0)
if (debug_https) { if (debugHttps) {
console.log(`${testname}: recode`) console.log(`${testname}: recode`)
console.log(JSON.stringify(decoded, null, 2)) console.log(JSON.stringify(decoded, null, 2))
} }
@ -681,25 +680,25 @@ const test_scvb_decode_encode = (t, testname, packetbuf, expected, skip_encode=f
} }
} }
const test_https_decode_encode = (t, testname, packetbuf, expected, skip_encode=false, skip_memcmp_bufs=false) => { const testHttpsDecodeEncode = (t, testname, packetbuf, expected, skipEncode = false, skipMemcmpBufs = false) => {
const decoded = packet.httpssvc.decode(packetbuf, 0) const decoded = packet.httpssvc.decode(packetbuf, 0)
if (debug_https) { if (debugHttps) {
console.log(`${testname}: decode:`) console.log(`${testname}: decode:`)
console.log(JSON.stringify(decoded, null, 2)) console.log(JSON.stringify(decoded, null, 2))
} }
t.ok(compare(t, decoded, expected), 'https ' + testname + ' decode') t.ok(compare(t, decoded, expected), 'https ' + testname + ' decode')
const encoded = packet.httpssvc.encode(expected) const encoded = packet.httpssvc.encode(expected)
if (!skip_encode) { if (!skipEncode) {
if (debug_https) { if (debugHttps) {
console.log(`${testname}: encode:`) console.log(`${testname}: encode:`)
hexdump(encoded) hexdump(encoded)
} }
if (!skip_memcmp_bufs) { if (!skipMemcmpBufs) {
t.ok(compare(t, packetbuf, encoded), 'https ' + testname + ' encode memcmp') t.ok(compare(t, packetbuf, encoded), 'https ' + testname + ' encode memcmp')
} }
// now decode the encoded buffer and check for sameness // now decode the encoded buffer and check for sameness
const recoded = packet.httpssvc.decode(encoded, 0) const recoded = packet.httpssvc.decode(encoded, 0)
if (debug_https) { if (debugHttps) {
console.log(`${testname}: recode`) console.log(`${testname}: recode`)
console.log(JSON.stringify(decoded, null, 2)) console.log(JSON.stringify(decoded, null, 2))
} }
@ -708,9 +707,9 @@ const test_https_decode_encode = (t, testname, packetbuf, expected, skip_encode=
return encoded return encoded
} }
const test_https_svcb_decode_encode = (t, testname, packetbuf, expected, skip_encode=false, skip_memcmp_bufs=false) => { const testHttpsSvcbDecodeEncode = (t, testname, packetbuf, expected, skipEncode = false, skipMemcmpBufs = false) => {
test_scvb_decode_encode(t, testname, packetbuf, expected, skip_encode, skip_memcmp_bufs) testScvbDecodeEncode(t, testname, packetbuf, expected, skipEncode, skipMemcmpBufs)
return test_https_decode_encode(t, testname, packetbuf, expected, skip_encode, skip_memcmp_bufs) return testHttpsDecodeEncode(t, testname, packetbuf, expected, skipEncode, skipMemcmpBufs)
} }
tape('https svcb', function (t) { tape('https svcb', function (t) {
@ -720,18 +719,18 @@ tape('https svcb', function (t) {
testEncoder(t, packet.svcb, { testEncoder(t, packet.svcb, {
priority: 16, priority: 16,
name: "foo.example.org", name: 'foo.example.org',
values: { values: {
mandatory: [ mandatory: [
"alpn", 'alpn',
"ipv4hint" 'ipv4hint'
], ],
alpn: [ alpn: [
"h2", 'h2',
"h3-19" 'h3-19'
], ],
ipv4hint: [ ipv4hint: [
"192.0.2.1" '192.0.2.1'
] ]
} }
} }
@ -739,29 +738,29 @@ tape('https svcb', function (t) {
testEncoder(t, packet.httpssvc, { testEncoder(t, packet.httpssvc, {
priority: 16, priority: 16,
name: "foo.example.org", name: 'foo.example.org',
values: { values: {
mandatory: [ mandatory: [
"alpn", 'alpn',
"ipv4hint" 'ipv4hint'
], ],
alpn: [ alpn: [
"h2", 'h2',
"h3-19" 'h3-19'
], ],
ipv4hint: [ ipv4hint: [
"192.0.2.1" '192.0.2.1'
] ]
} }
} }
) )
// https AliasMode // https AliasMode
test_https_svcb_decode_encode(t, 'rfc9460 case1 (AliasMode)', testHttpsSvcbDecodeEncode(t, 'rfc9460 case1 (AliasMode)',
unhexlify( unhexlify(
"00 13" + // rdata len '00 13' + // rdata len
"00 00" + // priority '00 00' + // priority
"03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00" //target '03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00' // target
), ),
{ {
priority: 0, priority: 0,
@ -770,11 +769,11 @@ tape('https svcb', function (t) {
) )
// https target name is "." // https target name is "."
test_https_svcb_decode_encode(t, 'rfc9460 case2 (target name ".")', testHttpsSvcbDecodeEncode(t, 'rfc9460 case2 (target name ".")',
unhexlify( unhexlify(
"00 03" + // rdata len '00 03' + // rdata len
"00 01" + // priority '00 01' + // priority
"00" // target (root label) '00' // target (root label)
), ),
{ {
priority: 1, priority: 1,
@ -783,14 +782,14 @@ tape('https svcb', function (t) {
) )
// https port // https port
test_https_svcb_decode_encode(t, 'rfc9460 case3 (port)', testHttpsSvcbDecodeEncode(t, 'rfc9460 case3 (port)',
unhexlify( unhexlify(
"00 19" + // rdata len '00 19' + // rdata len
"00 10" + // priority '00 10' + // priority
"03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00" + // target '03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00' + // target
"00 03" + // key 3 '00 03' + // key 3
"00 02" + // length 2 '00 02' + // length 2
"00 35" // value - target (root label) '00 35' // value - target (root label)
), ),
{ {
priority: 16, priority: 16,
@ -802,14 +801,14 @@ tape('https svcb', function (t) {
) )
// https generic key and value // https generic key and value
test_https_svcb_decode_encode(t, 'rfc9460 case4 (generic key,val)', testHttpsSvcbDecodeEncode(t, 'rfc9460 case4 (generic key,val)',
unhexlify( unhexlify(
"00 1c" + // rdata len '00 1c' + // rdata len
"00 01" + // priority '00 01' + // priority
"03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00" + // target '03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00' + // target
"02 9b" + // key 667 '02 9b' + // key 667
"00 05" + // length 5 '00 05' + // length 5
"68 65 6c 6c 6f" // value '68 65 6c 6c 6f' // value
), ),
{ {
priority: 1, priority: 1,
@ -818,67 +817,67 @@ tape('https svcb', function (t) {
key667: 'hello' key667: 'hello'
} }
}, },
true //skip_encode, we cannot encode an unknown key true // skipEncode, we cannot encode an unknown key
) )
// https generic key and value with decimal escape // https generic key and value with decimal escape
test_https_svcb_decode_encode(t, 'rfc9460 case5 (generic key,val with escape)', testHttpsSvcbDecodeEncode(t, 'rfc9460 case5 (generic key,val with escape)',
unhexlify( unhexlify(
"00 20" + // rdata len '00 20' + // rdata len
"00 01" + // priority '00 01' + // priority
"03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00" + // target '03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00' + // target
"02 9b" + // key 667 '02 9b' + // key 667
"00 09" + // length 9 '00 09' + // length 9
"68 65 6c 6c 6f d2 71 6f 6f" // value '68 65 6c 6c 6f d2 71 6f 6f' // value
), ),
{ {
priority: 1, priority: 1,
name: 'foo.example.com', name: 'foo.example.com',
values: { values: {
key667: unhexlify("68 65 6c 6c 6f d2 71 6f 6f").toString("utf-8") key667: unhexlify('68 65 6c 6c 6f d2 71 6f 6f').toString('utf-8')
}
}, },
}, true // skipEncode, we cannot encode an unknown key
true // skip_encode, we cannot encode an unknown key
) )
// https two quoted ipv6 hints // https two quoted ipv6 hints
test_https_svcb_decode_encode(t, 'rfc9460 case6 (ipv6hint)', testHttpsSvcbDecodeEncode(t, 'rfc9460 case6 (ipv6hint)',
unhexlify( unhexlify(
"00 37" + // rdata len '00 37' + // rdata len
"00 01" + // priority '00 01' + // priority
"03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00" + // target '03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00' + // target
"00 06" + // key 6 '00 06' + // key 6
"00 20" + // length 32 '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 00 00 01' + // first address
"20 01 0d b8 00 00 00 00 00 00 00 00 00 53 00 01" // second address '20 01 0d b8 00 00 00 00 00 00 00 00 00 53 00 01' // second address
), ),
{ {
priority: 1, priority: 1,
name: "foo.example.com", name: 'foo.example.com',
values: { values: {
ipv6hint: [ ipv6hint: [
"2001:db8::1", '2001:db8::1',
"2001:db8::53:1" '2001:db8::53:1'
] ]
} }
} }
) )
// https ipv6 hint using embedded ipv4 syntax [2001:db8:122:344::192.0.2.33] // https ipv6 hint using embedded ipv4 syntax [2001:db8:122:344::192.0.2.33]
test_https_svcb_decode_encode(t, 'rfc9460 case7 (ipv6hint v4 syntax)', testHttpsSvcbDecodeEncode(t, 'rfc9460 case7 (ipv6hint v4 syntax)',
unhexlify( unhexlify(
"00 23" + // rdata len '00 23' + // rdata len
"00 01" + // priority '00 01' + // priority
"07 65 78 61 6d 70 6c 65 03 63 6f 6d 00" + // target '07 65 78 61 6d 70 6c 65 03 63 6f 6d 00' + // target
"00 06" + // key 6 '00 06' + // key 6
"00 10" + // length 16 '00 10' + // length 16
"20 01 0d b8 01 22 03 44 00 00 00 00 c0 00 02 21" // address '20 01 0d b8 01 22 03 44 00 00 00 00 c0 00 02 21' // address
), ),
{ {
priority: 1, priority: 1,
name: "example.com", name: 'example.com',
values: { values: {
ipv6hint: [ ip.v6.decode(ip.v6.encode("2001:db8:122:344::192.0.2.33")) ] ipv6hint: [ ip.v6.decode(ip.v6.encode('2001:db8:122:344::192.0.2.33')) ]
} }
} }
) )
@ -891,81 +890,81 @@ tape('https svcb', function (t) {
// //
// note: this may not encode to the same buffer due to internal js // note: this may not encode to the same buffer due to internal js
// ordering of the `values` object storing the params // ordering of the `values` object storing the params
test_https_svcb_decode_encode(t, 'rfc9460 case8 (alpn,mandatory,ipv4hint)', testHttpsSvcbDecodeEncode(t, 'rfc9460 case8 (alpn,mandatory,ipv4hint)',
unhexlify( unhexlify(
"00 30" + // rdata len '00 30' + // rdata len
"00 10" + // priority '00 10' + // priority
"03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 6f 72 67 00" + // target '03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 6f 72 67 00' + // target
"00 00" + // key 0 '00 00' + // key 0
"00 04" + // param length 4 '00 04' + // param length 4
"00 01" + // value: key 1 '00 01' + // value: key 1
"00 04" + // value: key 4 '00 04' + // value: key 4
"00 01" + // key 1 '00 01' + // key 1
"00 09" + // param length 9 '00 09' + // param length 9
"02" + // alpn length 2 '02' + // alpn length 2
"68 32" + // alpn value '68 32' + // alpn value
"05" + // alpn length 5 '05' + // alpn length 5
"68 33 2d 31 39" + // alpn value '68 33 2d 31 39' + // alpn value
"00 04" + // key 4 '00 04' + // key 4
"00 04" + // param length 4 '00 04' + // param length 4
"c0 00 02 01" // param value 'c0 00 02 01' // param value
), ),
{ {
priority: 16, priority: 16,
name: "foo.example.org", name: 'foo.example.org',
values: { values: {
mandatory: [ mandatory: [
"alpn", 'alpn',
"ipv4hint" 'ipv4hint'
], ],
alpn: [ alpn: [
"h2", 'h2',
"h3-19" 'h3-19'
], ],
ipv4hint: [ ipv4hint: [
"192.0.2.1" '192.0.2.1'
] ]
} }
}, },
false, // skip_encode: false false, // skipEncode: false
true, // skip_memcmp_bufs: true, do not directly memcmp the resulting bufs, see comment above true // skipMemcmpBufs: true, do not directly memcmp the resulting bufs, see comment above
) )
t.end() t.end()
}) })
tape('cloudflare real world svcb/https', (t) => { tape('cloudflare real world svcb/https', (t) => {
const https_buf = unhexlify( const httpsBuf = unhexlify(
"ef 23 81 80 00 01 00 01 00 00 00 01 09 63 6f 6d" + '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" + '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" + '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" + '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" + '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" + '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" + '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 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 00 68 12 03 43 00 00 29 02 00' +
"00 00 00 00 00 00" '00 00 00 00 00 00'
) )
const svcb_buf = unhexlify( const svcbBuf = unhexlify(
"ef 23 81 80 00 01 00 01 00 00 00 01 09 63 6f 6d" + '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" + '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" + '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" + '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" + '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" + '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" + '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 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 00 68 12 03 43 00 00 29 02 00' +
"00 00 00 00 00 00" '00 00 00 00 00 00'
) )
let expected = { let expected = {
id: 61219, id: 61219,
type: "response", type: 'response',
flags: 384, flags: 384,
flag_qr: true, flag_qr: true,
opcode: "QUERY", opcode: 'QUERY',
flag_aa: false, flag_aa: false,
flag_tc: false, flag_tc: false,
flag_rd: true, flag_rd: true,
@ -973,36 +972,36 @@ tape('cloudflare real world svcb/https', (t) => {
flag_z: false, flag_z: false,
flag_ad: false, flag_ad: false,
flag_cd: false, flag_cd: false,
rcode: "NOERROR", rcode: 'NOERROR',
questions: [ questions: [
{ {
name: "community.cloudflare.com", name: 'community.cloudflare.com',
type: "HTTPS", type: 'HTTPS',
class: "IN" class: 'IN'
} }
], ],
answers: [ answers: [
{ {
name: "community.cloudflare.com", name: 'community.cloudflare.com',
type: "HTTPS", type: 'HTTPS',
ttl: 60, ttl: 60,
class: "IN", class: 'IN',
flush: false, flush: false,
data: { data: {
priority: 1, priority: 1,
name: ".", name: '.',
values: { values: {
alpn: [ alpn: [
"h3", 'h3',
"h2" 'h2'
], ],
ipv4hint: [ ipv4hint: [
"104.18.2.67", '104.18.2.67',
"104.18.3.67" '104.18.3.67'
], ],
ipv6hint: [ ipv6hint: [
"2606:4700::6812:243", '2606:4700::6812:243',
"2606:4700::6812:343" '2606:4700::6812:343'
] ]
} }
} }
@ -1011,8 +1010,8 @@ tape('cloudflare real world svcb/https', (t) => {
authorities: [], authorities: [],
additionals: [ additionals: [
{ {
name: ".", name: '.',
type: "OPT", type: 'OPT',
udpPayloadSize: 512, udpPayloadSize: 512,
extendedRcode: 0, extendedRcode: 0,
ednsVersion: 0, ednsVersion: 0,
@ -1023,52 +1022,51 @@ tape('cloudflare real world svcb/https', (t) => {
] ]
} }
const decoded_https = packet.decode(https_buf) const decodedHttps = packet.decode(httpsBuf)
t.ok(decoded_https, "cloudflare real world https decoded") t.ok(decodedHttps, 'cloudflare real world https decoded')
if (debug_https) { if (debugHttps) {
console.log(`cloudflare real world: decoded_https:`) console.log(`cloudflare real world: decodedHttps:`)
console.log(JSON.stringify(decoded_https, null, 2)) console.log(JSON.stringify(decodedHttps, null, 2))
} }
t.ok(compare(t, decoded_https, expected), "cloudflare real world https compare") t.ok(compare(t, decodedHttps, expected), 'cloudflare real world https compare')
const decoded_svcb = packet.decode(svcb_buf) const decodedSvcb = packet.decode(svcbBuf)
t.ok(decoded_svcb, "cloudflare real world svcb decoded") t.ok(decodedSvcb, 'cloudflare real world svcb decoded')
if (debug_https) { if (debugHttps) {
console.log(`cloudflare real world: decoded_svcb:`) console.log(`cloudflare real world: decodedSvcb:`)
console.log(JSON.stringify(decoded_svcb, null, 2)) console.log(JSON.stringify(decodedSvcb, null, 2))
} }
expected.questions[0].type = expected.answers[0].type = "SVCB" expected.questions[0].type = expected.answers[0].type = 'SVCB'
t.ok(compare(t, decoded_svcb, expected), "cloudflare real world svcb compare") t.ok(compare(t, decodedSvcb, expected), 'cloudflare real world svcb compare')
t.end() t.end()
}) })
tape('google resolver SVCB real world', function (t) { tape('google resolver SVCB real world', function (t) {
const svcb_buf = unhexlify( const svcbBuf = unhexlify(
"d0 90 85 80 00 01" + 'd0 90 85 80 00 01' +
"00 02 00 00 00 04 04 5f 64 6e 73 08 72 65 73 6f" + '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" + '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" + '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" + '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" + '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" + '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" + '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" + '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" + '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" + '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" + '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" + '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 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" '00 00 00 00 00 00 00 00 88 44'
) )
const expected = { const expected = {
id: 53392, id: 53392,
type: "response", type: 'response',
flags: 1408, flags: 1408,
flag_qr: true, flag_qr: true,
opcode: "QUERY", opcode: 'QUERY',
flag_aa: true, flag_aa: true,
flag_tc: false, flag_tc: false,
flag_rd: true, flag_rd: true,
@ -1076,46 +1074,46 @@ tape('google resolver SVCB real world', function (t) {
flag_z: false, flag_z: false,
flag_ad: false, flag_ad: false,
flag_cd: false, flag_cd: false,
rcode: "NOERROR", rcode: 'NOERROR',
questions: [ questions: [
{ {
name: "_dns.resolver.arpa", name: '_dns.resolver.arpa',
type: "SVCB", type: 'SVCB',
class: "IN" class: 'IN'
} }
], ],
answers: [ answers: [
{ {
name: "_dns.resolver.arpa", name: '_dns.resolver.arpa',
type: "SVCB", type: 'SVCB',
ttl: 86400, ttl: 86400,
class: "IN", class: 'IN',
flush: false, flush: false,
data: { data: {
priority: 1, priority: 1,
name: "dns.google", name: 'dns.google',
values: { values: {
alpn: [ alpn: [
"dot" 'dot'
] ]
} }
} }
}, },
{ {
name: "_dns.resolver.arpa", name: '_dns.resolver.arpa',
type: "SVCB", type: 'SVCB',
ttl: 86400, ttl: 86400,
class: "IN", class: 'IN',
flush: false, flush: false,
data: { data: {
priority: 2, priority: 2,
name: "dns.google", name: 'dns.google',
values: { values: {
alpn: [ alpn: [
"h2", 'h2',
"h3" 'h3'
], ],
dohpath: "/dns-query{?dns}" dohpath: '/dns-query{?dns}'
} }
} }
} }
@ -1123,53 +1121,53 @@ tape('google resolver SVCB real world', function (t) {
authorities: [], authorities: [],
additionals: [ additionals: [
{ {
name: "dns.google", name: 'dns.google',
type: "A", type: 'A',
ttl: 86400, ttl: 86400,
class: "IN", class: 'IN',
flush: false, flush: false,
data: "8.8.8.8" data: '8.8.8.8'
}, },
{ {
name: "dns.google", name: 'dns.google',
type: "A", type: 'A',
ttl: 86400, ttl: 86400,
class: "IN", class: 'IN',
flush: false, flush: false,
data: "8.8.4.4" data: '8.8.4.4'
}, },
{ {
name: "dns.google", name: 'dns.google',
type: "AAAA", type: 'AAAA',
ttl: 86400, ttl: 86400,
class: "IN", class: 'IN',
flush: false, flush: false,
data: "2001:4860:4860::8888" data: '2001:4860:4860::8888'
}, },
{ {
name: "dns.google", name: 'dns.google',
type: "AAAA", type: 'AAAA',
ttl: 86400, ttl: 86400,
class: "IN", class: 'IN',
flush: false, flush: false,
data: "2001:4860:4860::8844" data: '2001:4860:4860::8844'
} }
] ]
} }
const decoded_svcb = packet.decode(svcb_buf) const decodedSvcb = packet.decode(svcbBuf)
t.ok(decoded_svcb, "google real world svcb decoded") t.ok(decodedSvcb, 'google real world svcb decoded')
if (debug_https) { if (debugHttps) {
console.log(`google real world svcb: decoded_svcb:`) console.log(`google real world svcb: decodedSvcb:`)
console.log(JSON.stringify(decoded_svcb, null, 2)) console.log(JSON.stringify(decodedSvcb, null, 2))
} }
t.ok(compare(t, decoded_svcb, expected), "google real world svcb compare") t.ok(compare(t, decodedSvcb, expected), 'google real world svcb compare')
// now test encoding and decoding the individual answer data // now test encoding and decoding the individual answer data
for (let answer of expected.answers) { for (let answer of expected.answers) {
const encoded_data = packet.svcb.encode(answer.data) const encodedData = packet.svcb.encode(answer.data)
const decoded_data = packet.svcb.decode(encoded_data) const decodedData = packet.svcb.decode(encodedData)
t.ok(compare(t, answer.data, decoded_data), "google real world answer recode") t.ok(compare(t, answer.data, decodedData), 'google real world answer recode')
} }
t.end() t.end()
@ -1177,7 +1175,6 @@ tape('google resolver SVCB real world', function (t) {
// </HTTPS SVCB test cases> // </HTTPS SVCB test cases>
tape('unpack', function (t) { tape('unpack', function (t) {
const buf = Buffer.from([ const buf = Buffer.from([
0x00, 0x79, 0x00, 0x79,