From 74972afbbfc58d43b4d900788829a56d81c3e77b Mon Sep 17 00:00:00 2001 From: Justin Fisher Date: Wed, 9 Jul 2025 16:07:20 -0400 Subject: [PATCH] Added dohpath SvcParam --- index.js | 15 ++++++- test.js | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 91c4b37..d9f1f41 100644 --- a/index.js +++ b/index.js @@ -1484,6 +1484,7 @@ svcparam.keyToNumber = function(keyName) { case 'ipv4hint' : return 4 case 'echconfig' : return 5 case 'ipv6hint' : return 6 + case 'dohpath' : return 7 case 'odoh' : return 32769 case 'key65535' : return 65535 } @@ -1503,6 +1504,7 @@ svcparam.numberToKeyName = function(number) { case 4 : return 'ipv4hint' case 5 : return 'echconfig' case 6 : return 'ipv6hint' + case 7 : return 'dohpath' case 32769 : return 'odoh' } @@ -1611,7 +1613,14 @@ svcparam.encode = function(param, buf, offset) { offset += 16 svcparam.encode.bytes += 16 } - } else if (key == 32769) { //odoh + } 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 @@ -1722,6 +1731,7 @@ svcparam.decode = function (buf, offset) { param.value = ips } break + case 'dohpath': default: param.value = buf.toString('utf-8', offset, offset + len) break @@ -1766,6 +1776,9 @@ svcparam.encodingLength = function (param) { } return 4 + param.value.length } + case 'dohpath': { + return 4 + param.value.length + } case 'key65535' : return 4 default: return 4 // unknown option } diff --git a/test.js b/test.js index 4b8f79f..a0281a6 100644 --- a/test.js +++ b/test.js @@ -1044,6 +1044,137 @@ tape('cloudflare real world svcb/https', (t) => { }) +tape('google resolver SVCB real world', function (t) { + const svcb_buf = 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 decoded_svcb = packet.decode(svcb_buf) + t.ok(decoded_svcb, "google real world svcb decoded") + if (debug_https) { + console.log(`google real world svcb: decoded_svcb:`) + console.log(JSON.stringify(decoded_svcb, null, 2)) + } + t.ok(compare(t, decoded_svcb, expected), "google real world svcb compare") + + // now test encoding and decoding the individual answer data + for (let answer of expected.answers) { + const encoded_data = packet.svcb.encode(answer.data) + const decoded_data = packet.svcb.decode(encoded_data) + t.ok(compare(t, answer.data, decoded_data), "google real world answer recode") + } + + t.end() +}) + //