tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

index.js (46637B)


      1 'use strict'
      2 
      3 const types = require('./types')
      4 const rcodes = require('./rcodes')
      5 exports.rcodes = rcodes;
      6 const opcodes = require('./opcodes')
      7 const classes = require('./classes')
      8 const optioncodes = require('./optioncodes')
      9 const ip = require('../node_ip')
     10 
     11 const QUERY_FLAG = 0
     12 const RESPONSE_FLAG = 1 << 15
     13 const FLUSH_MASK = 1 << 15
     14 const NOT_FLUSH_MASK = ~FLUSH_MASK
     15 const QU_MASK = 1 << 15
     16 const NOT_QU_MASK = ~QU_MASK
     17 
     18 const name = exports.txt = exports.name = {}
     19 
     20 name.encode = function (str, buf, offset) {
     21  if (!buf) buf = Buffer.allocUnsafe(name.encodingLength(str))
     22  if (!offset) offset = 0
     23  const oldOffset = offset
     24 
     25  // strip leading and trailing .
     26  const n = str.replace(/^\.|\.$/gm, '')
     27  if (n.length) {
     28    const list = n.split('.')
     29 
     30    for (let i = 0; i < list.length; i++) {
     31      const len = buf.write(list[i], offset + 1)
     32      buf[offset] = len
     33      offset += len + 1
     34    }
     35  }
     36 
     37  buf[offset++] = 0
     38 
     39  name.encode.bytes = offset - oldOffset
     40  return buf
     41 }
     42 
     43 name.encode.bytes = 0
     44 
     45 name.decode = function (buf, offset) {
     46  if (!offset) offset = 0
     47 
     48  const list = []
     49  const oldOffset = offset
     50  let len = buf[offset++]
     51 
     52  if (len === 0) {
     53    name.decode.bytes = 1
     54    return '.'
     55  }
     56  if (len >= 0xc0) {
     57    const res = name.decode(buf, buf.readUInt16BE(offset - 1) - 0xc000)
     58    name.decode.bytes = 2
     59    return res
     60  }
     61 
     62  while (len) {
     63    if (len >= 0xc0) {
     64      list.push(name.decode(buf, buf.readUInt16BE(offset - 1) - 0xc000))
     65      offset++
     66      break
     67    }
     68 
     69    list.push(buf.toString('utf-8', offset, offset + len))
     70    offset += len
     71    len = buf[offset++]
     72  }
     73 
     74  name.decode.bytes = offset - oldOffset
     75  return list.join('.')
     76 }
     77 
     78 name.decode.bytes = 0
     79 
     80 name.encodingLength = function (n) {
     81  if (n === '.') return 1
     82  return Buffer.byteLength(n) + 2
     83 }
     84 
     85 const string = {}
     86 
     87 string.encode = function (s, buf, offset) {
     88  if (!buf) buf = Buffer.allocUnsafe(string.encodingLength(s))
     89  if (!offset) offset = 0
     90 
     91  const len = buf.write(s, offset + 1)
     92  buf[offset] = len
     93  string.encode.bytes = len + 1
     94  return buf
     95 }
     96 
     97 string.encode.bytes = 0
     98 
     99 string.decode = function (buf, offset) {
    100  if (!offset) offset = 0
    101 
    102  const len = buf[offset]
    103  const s = buf.toString('utf-8', offset + 1, offset + 1 + len)
    104  string.decode.bytes = len + 1
    105  return s
    106 }
    107 
    108 string.decode.bytes = 0
    109 
    110 string.encodingLength = function (s) {
    111  return Buffer.byteLength(s) + 1
    112 }
    113 
    114 const header = {}
    115 
    116 header.encode = function (h, buf, offset) {
    117  if (!buf) buf = header.encodingLength(h)
    118  if (!offset) offset = 0
    119 
    120  const flags = (h.flags || 0) & 32767
    121  const type = h.type === 'response' ? RESPONSE_FLAG : QUERY_FLAG
    122 
    123  buf.writeUInt16BE(h.id || 0, offset)
    124  buf.writeUInt16BE(flags | type, offset + 2)
    125  buf.writeUInt16BE(h.questions.length, offset + 4)
    126  buf.writeUInt16BE(h.answers.length, offset + 6)
    127  buf.writeUInt16BE(h.authorities.length, offset + 8)
    128  buf.writeUInt16BE(h.additionals.length, offset + 10)
    129 
    130  return buf
    131 }
    132 
    133 header.encode.bytes = 12
    134 
    135 header.decode = function (buf, offset) {
    136  if (!offset) offset = 0
    137  if (buf.length < 12) throw new Error('Header must be 12 bytes')
    138  const flags = buf.readUInt16BE(offset + 2)
    139 
    140  return {
    141    id: buf.readUInt16BE(offset),
    142    type: flags & RESPONSE_FLAG ? 'response' : 'query',
    143    flags: flags & 32767,
    144    flag_qr: ((flags >> 15) & 0x1) === 1,
    145    opcode: opcodes.toString((flags >> 11) & 0xf),
    146    flag_aa: ((flags >> 10) & 0x1) === 1,
    147    flag_tc: ((flags >> 9) & 0x1) === 1,
    148    flag_rd: ((flags >> 8) & 0x1) === 1,
    149    flag_ra: ((flags >> 7) & 0x1) === 1,
    150    flag_z: ((flags >> 6) & 0x1) === 1,
    151    flag_ad: ((flags >> 5) & 0x1) === 1,
    152    flag_cd: ((flags >> 4) & 0x1) === 1,
    153    rcode: rcodes.toString(flags & 0xf),
    154    questions: new Array(buf.readUInt16BE(offset + 4)),
    155    answers: new Array(buf.readUInt16BE(offset + 6)),
    156    authorities: new Array(buf.readUInt16BE(offset + 8)),
    157    additionals: new Array(buf.readUInt16BE(offset + 10))
    158  }
    159 }
    160 
    161 header.decode.bytes = 12
    162 
    163 header.encodingLength = function () {
    164  return 12
    165 }
    166 
    167 const runknown = exports.unknown = {}
    168 
    169 runknown.encode = function (data, buf, offset) {
    170  if (!buf) buf = Buffer.allocUnsafe(runknown.encodingLength(data))
    171  if (!offset) offset = 0
    172 
    173  buf.writeUInt16BE(data.length, offset)
    174  data.copy(buf, offset + 2)
    175 
    176  runknown.encode.bytes = data.length + 2
    177  return buf
    178 }
    179 
    180 runknown.encode.bytes = 0
    181 
    182 runknown.decode = function (buf, offset) {
    183  if (!offset) offset = 0
    184 
    185  const len = buf.readUInt16BE(offset)
    186  const data = buf.slice(offset + 2, offset + 2 + len)
    187  runknown.decode.bytes = len + 2
    188  return data
    189 }
    190 
    191 runknown.decode.bytes = 0
    192 
    193 runknown.encodingLength = function (data) {
    194  return data.length + 2
    195 }
    196 
    197 const rns = exports.ns = {}
    198 
    199 rns.encode = function (data, buf, offset) {
    200  if (!buf) buf = Buffer.allocUnsafe(rns.encodingLength(data))
    201  if (!offset) offset = 0
    202 
    203  name.encode(data, buf, offset + 2)
    204  buf.writeUInt16BE(name.encode.bytes, offset)
    205  rns.encode.bytes = name.encode.bytes + 2
    206  return buf
    207 }
    208 
    209 rns.encode.bytes = 0
    210 
    211 rns.decode = function (buf, offset) {
    212  if (!offset) offset = 0
    213 
    214  const len = buf.readUInt16BE(offset)
    215  const dd = name.decode(buf, offset + 2)
    216 
    217  rns.decode.bytes = len + 2
    218  return dd
    219 }
    220 
    221 rns.decode.bytes = 0
    222 
    223 rns.encodingLength = function (data) {
    224  return name.encodingLength(data) + 2
    225 }
    226 
    227 const rsoa = exports.soa = {}
    228 
    229 rsoa.encode = function (data, buf, offset) {
    230  if (!buf) buf = Buffer.allocUnsafe(rsoa.encodingLength(data))
    231  if (!offset) offset = 0
    232 
    233  const oldOffset = offset
    234  offset += 2
    235  name.encode(data.mname, buf, offset)
    236  offset += name.encode.bytes
    237  name.encode(data.rname, buf, offset)
    238  offset += name.encode.bytes
    239  buf.writeUInt32BE(data.serial || 0, offset)
    240  offset += 4
    241  buf.writeUInt32BE(data.refresh || 0, offset)
    242  offset += 4
    243  buf.writeUInt32BE(data.retry || 0, offset)
    244  offset += 4
    245  buf.writeUInt32BE(data.expire || 0, offset)
    246  offset += 4
    247  buf.writeUInt32BE(data.minimum || 0, offset)
    248  offset += 4
    249 
    250  buf.writeUInt16BE(offset - oldOffset - 2, oldOffset)
    251  rsoa.encode.bytes = offset - oldOffset
    252  return buf
    253 }
    254 
    255 rsoa.encode.bytes = 0
    256 
    257 rsoa.decode = function (buf, offset) {
    258  if (!offset) offset = 0
    259 
    260  const oldOffset = offset
    261 
    262  const data = {}
    263  offset += 2
    264  data.mname = name.decode(buf, offset)
    265  offset += name.decode.bytes
    266  data.rname = name.decode(buf, offset)
    267  offset += name.decode.bytes
    268  data.serial = buf.readUInt32BE(offset)
    269  offset += 4
    270  data.refresh = buf.readUInt32BE(offset)
    271  offset += 4
    272  data.retry = buf.readUInt32BE(offset)
    273  offset += 4
    274  data.expire = buf.readUInt32BE(offset)
    275  offset += 4
    276  data.minimum = buf.readUInt32BE(offset)
    277  offset += 4
    278 
    279  rsoa.decode.bytes = offset - oldOffset
    280  return data
    281 }
    282 
    283 rsoa.decode.bytes = 0
    284 
    285 rsoa.encodingLength = function (data) {
    286  return 22 + name.encodingLength(data.mname) + name.encodingLength(data.rname)
    287 }
    288 
    289 const rtxt = exports.txt = {}
    290 
    291 rtxt.encode = function (data, buf, offset) {
    292  if (!Array.isArray(data)) data = [data]
    293  for (let i = 0; i < data.length; i++) {
    294    if (typeof data[i] === 'string') {
    295      data[i] = Buffer.from(data[i])
    296    }
    297    if (!Buffer.isBuffer(data[i])) {
    298      throw new Error('Must be a Buffer')
    299    }
    300  }
    301 
    302  if (!buf) buf = Buffer.allocUnsafe(rtxt.encodingLength(data))
    303  if (!offset) offset = 0
    304 
    305  const oldOffset = offset
    306  offset += 2
    307 
    308  data.forEach(function (d) {
    309    buf[offset++] = d.length
    310    d.copy(buf, offset, 0, d.length)
    311    offset += d.length
    312  })
    313 
    314  buf.writeUInt16BE(offset - oldOffset - 2, oldOffset)
    315  rtxt.encode.bytes = offset - oldOffset
    316  return buf
    317 }
    318 
    319 rtxt.encode.bytes = 0
    320 
    321 rtxt.decode = function (buf, offset) {
    322  if (!offset) offset = 0
    323  const oldOffset = offset
    324  let remaining = buf.readUInt16BE(offset)
    325  offset += 2
    326 
    327  let data = []
    328  while (remaining > 0) {
    329    const len = buf[offset++]
    330    --remaining
    331    if (remaining < len) {
    332      throw new Error('Buffer overflow')
    333    }
    334    data.push(buf.slice(offset, offset + len))
    335    offset += len
    336    remaining -= len
    337  }
    338 
    339  rtxt.decode.bytes = offset - oldOffset
    340  return data
    341 }
    342 
    343 rtxt.decode.bytes = 0
    344 
    345 rtxt.encodingLength = function (data) {
    346  if (!Array.isArray(data)) data = [data]
    347  let length = 2
    348  data.forEach(function (buf) {
    349    if (typeof buf === 'string') {
    350      length += Buffer.byteLength(buf) + 1
    351    } else {
    352      length += buf.length + 1
    353    }
    354  })
    355  return length
    356 }
    357 
    358 const rnull = exports.null = {}
    359 
    360 rnull.encode = function (data, buf, offset) {
    361  if (!buf) buf = Buffer.allocUnsafe(rnull.encodingLength(data))
    362  if (!offset) offset = 0
    363 
    364  if (typeof data === 'string') data = Buffer.from(data)
    365  if (!data) data = Buffer.allocUnsafe(0)
    366 
    367  const oldOffset = offset
    368  offset += 2
    369 
    370  const len = data.length
    371  data.copy(buf, offset, 0, len)
    372  offset += len
    373 
    374  buf.writeUInt16BE(offset - oldOffset - 2, oldOffset)
    375  rnull.encode.bytes = offset - oldOffset
    376  return buf
    377 }
    378 
    379 rnull.encode.bytes = 0
    380 
    381 rnull.decode = function (buf, offset) {
    382  if (!offset) offset = 0
    383  const oldOffset = offset
    384  const len = buf.readUInt16BE(offset)
    385 
    386  offset += 2
    387 
    388  const data = buf.slice(offset, offset + len)
    389  offset += len
    390 
    391  rnull.decode.bytes = offset - oldOffset
    392  return data
    393 }
    394 
    395 rnull.decode.bytes = 0
    396 
    397 rnull.encodingLength = function (data) {
    398  if (!data) return 2
    399  return (Buffer.isBuffer(data) ? data.length : Buffer.byteLength(data)) + 2
    400 }
    401 
    402 const rhinfo = exports.hinfo = {}
    403 
    404 rhinfo.encode = function (data, buf, offset) {
    405  if (!buf) buf = Buffer.allocUnsafe(rhinfo.encodingLength(data))
    406  if (!offset) offset = 0
    407 
    408  const oldOffset = offset
    409  offset += 2
    410  string.encode(data.cpu, buf, offset)
    411  offset += string.encode.bytes
    412  string.encode(data.os, buf, offset)
    413  offset += string.encode.bytes
    414  buf.writeUInt16BE(offset - oldOffset - 2, oldOffset)
    415  rhinfo.encode.bytes = offset - oldOffset
    416  return buf
    417 }
    418 
    419 rhinfo.encode.bytes = 0
    420 
    421 rhinfo.decode = function (buf, offset) {
    422  if (!offset) offset = 0
    423 
    424  const oldOffset = offset
    425 
    426  const data = {}
    427  offset += 2
    428  data.cpu = string.decode(buf, offset)
    429  offset += string.decode.bytes
    430  data.os = string.decode(buf, offset)
    431  offset += string.decode.bytes
    432  rhinfo.decode.bytes = offset - oldOffset
    433  return data
    434 }
    435 
    436 rhinfo.decode.bytes = 0
    437 
    438 rhinfo.encodingLength = function (data) {
    439  return string.encodingLength(data.cpu) + string.encodingLength(data.os) + 2
    440 }
    441 
    442 const rptr = exports.ptr = {}
    443 const rcname = exports.cname = rptr
    444 const rdname = exports.dname = rptr
    445 
    446 rptr.encode = function (data, buf, offset) {
    447  if (!buf) buf = Buffer.allocUnsafe(rptr.encodingLength(data))
    448  if (!offset) offset = 0
    449 
    450  name.encode(data, buf, offset + 2)
    451  buf.writeUInt16BE(name.encode.bytes, offset)
    452  rptr.encode.bytes = name.encode.bytes + 2
    453  return buf
    454 }
    455 
    456 rptr.encode.bytes = 0
    457 
    458 rptr.decode = function (buf, offset) {
    459  if (!offset) offset = 0
    460 
    461  const data = name.decode(buf, offset + 2)
    462  rptr.decode.bytes = name.decode.bytes + 2
    463  return data
    464 }
    465 
    466 rptr.decode.bytes = 0
    467 
    468 rptr.encodingLength = function (data) {
    469  return name.encodingLength(data) + 2
    470 }
    471 
    472 const rsrv = exports.srv = {}
    473 
    474 rsrv.encode = function (data, buf, offset) {
    475  if (!buf) buf = Buffer.allocUnsafe(rsrv.encodingLength(data))
    476  if (!offset) offset = 0
    477 
    478  buf.writeUInt16BE(data.priority || 0, offset + 2)
    479  buf.writeUInt16BE(data.weight || 0, offset + 4)
    480  buf.writeUInt16BE(data.port || 0, offset + 6)
    481  name.encode(data.target, buf, offset + 8)
    482 
    483  const len = name.encode.bytes + 6
    484  buf.writeUInt16BE(len, offset)
    485 
    486  rsrv.encode.bytes = len + 2
    487  return buf
    488 }
    489 
    490 rsrv.encode.bytes = 0
    491 
    492 rsrv.decode = function (buf, offset) {
    493  if (!offset) offset = 0
    494 
    495  const len = buf.readUInt16BE(offset)
    496 
    497  const data = {}
    498  data.priority = buf.readUInt16BE(offset + 2)
    499  data.weight = buf.readUInt16BE(offset + 4)
    500  data.port = buf.readUInt16BE(offset + 6)
    501  data.target = name.decode(buf, offset + 8)
    502 
    503  rsrv.decode.bytes = len + 2
    504  return data
    505 }
    506 
    507 rsrv.decode.bytes = 0
    508 
    509 rsrv.encodingLength = function (data) {
    510  return 8 + name.encodingLength(data.target)
    511 }
    512 
    513 const rcaa = exports.caa = {}
    514 
    515 rcaa.ISSUER_CRITICAL = 1 << 7
    516 
    517 rcaa.encode = function (data, buf, offset) {
    518  const len = rcaa.encodingLength(data)
    519 
    520  if (!buf) buf = Buffer.allocUnsafe(rcaa.encodingLength(data))
    521  if (!offset) offset = 0
    522 
    523  if (data.issuerCritical) {
    524    data.flags = rcaa.ISSUER_CRITICAL
    525  }
    526 
    527  buf.writeUInt16BE(len - 2, offset)
    528  offset += 2
    529  buf.writeUInt8(data.flags || 0, offset)
    530  offset += 1
    531  string.encode(data.tag, buf, offset)
    532  offset += string.encode.bytes
    533  buf.write(data.value, offset)
    534  offset += Buffer.byteLength(data.value)
    535 
    536  rcaa.encode.bytes = len
    537  return buf
    538 }
    539 
    540 rcaa.encode.bytes = 0
    541 
    542 rcaa.decode = function (buf, offset) {
    543  if (!offset) offset = 0
    544 
    545  const len = buf.readUInt16BE(offset)
    546  offset += 2
    547 
    548  const oldOffset = offset
    549  const data = {}
    550  data.flags = buf.readUInt8(offset)
    551  offset += 1
    552  data.tag = string.decode(buf, offset)
    553  offset += string.decode.bytes
    554  data.value = buf.toString('utf-8', offset, oldOffset + len)
    555 
    556  data.issuerCritical = !!(data.flags & rcaa.ISSUER_CRITICAL)
    557 
    558  rcaa.decode.bytes = len + 2
    559 
    560  return data
    561 }
    562 
    563 rcaa.decode.bytes = 0
    564 
    565 rcaa.encodingLength = function (data) {
    566  return string.encodingLength(data.tag) + string.encodingLength(data.value) + 2
    567 }
    568 
    569 const rmx = exports.mx = {}
    570 
    571 rmx.encode = function (data, buf, offset) {
    572  if (!buf) buf = Buffer.allocUnsafe(rmx.encodingLength(data))
    573  if (!offset) offset = 0
    574 
    575  const oldOffset = offset
    576  offset += 2
    577  buf.writeUInt16BE(data.preference || 0, offset)
    578  offset += 2
    579  name.encode(data.exchange, buf, offset)
    580  offset += name.encode.bytes
    581 
    582  buf.writeUInt16BE(offset - oldOffset - 2, oldOffset)
    583  rmx.encode.bytes = offset - oldOffset
    584  return buf
    585 }
    586 
    587 rmx.encode.bytes = 0
    588 
    589 rmx.decode = function (buf, offset) {
    590  if (!offset) offset = 0
    591 
    592  const oldOffset = offset
    593 
    594  const data = {}
    595  offset += 2
    596  data.preference = buf.readUInt16BE(offset)
    597  offset += 2
    598  data.exchange = name.decode(buf, offset)
    599  offset += name.decode.bytes
    600 
    601  rmx.decode.bytes = offset - oldOffset
    602  return data
    603 }
    604 
    605 rmx.encodingLength = function (data) {
    606  return 4 + name.encodingLength(data.exchange)
    607 }
    608 
    609 const ra = exports.a = {}
    610 
    611 ra.encode = function (host, buf, offset) {
    612  if (!buf) buf = Buffer.allocUnsafe(ra.encodingLength(host))
    613  if (!offset) offset = 0
    614 
    615  buf.writeUInt16BE(4, offset)
    616  offset += 2
    617  ip.toBuffer(host, buf, offset)
    618  ra.encode.bytes = 6
    619  return buf
    620 }
    621 
    622 ra.encode.bytes = 0
    623 
    624 ra.decode = function (buf, offset) {
    625  if (!offset) offset = 0
    626 
    627  offset += 2
    628  const host = ip.toString(buf, offset, 4)
    629  ra.decode.bytes = 6
    630  return host
    631 }
    632 ra.decode.bytes = 0
    633 
    634 ra.encodingLength = function () {
    635  return 6
    636 }
    637 
    638 const raaaa = exports.aaaa = {}
    639 
    640 raaaa.encode = function (host, buf, offset) {
    641  if (!buf) buf = Buffer.allocUnsafe(raaaa.encodingLength(host))
    642  if (!offset) offset = 0
    643 
    644  buf.writeUInt16BE(16, offset)
    645  offset += 2
    646  ip.toBuffer(host, buf, offset)
    647  raaaa.encode.bytes = 18
    648  return buf
    649 }
    650 
    651 raaaa.encode.bytes = 0
    652 
    653 raaaa.decode = function (buf, offset) {
    654  if (!offset) offset = 0
    655 
    656  offset += 2
    657  const host = ip.toString(buf, offset, 16)
    658  raaaa.decode.bytes = 18
    659  return host
    660 }
    661 
    662 raaaa.decode.bytes = 0
    663 
    664 raaaa.encodingLength = function () {
    665  return 18
    666 }
    667 
    668 const roption = exports.option = {}
    669 
    670 roption.encode = function (option, buf, offset) {
    671  if (!buf) buf = Buffer.allocUnsafe(roption.encodingLength(option))
    672  if (!offset) offset = 0
    673  const oldOffset = offset
    674 
    675  const code = optioncodes.toCode(option.code)
    676  buf.writeUInt16BE(code, offset)
    677  offset += 2
    678  if (option.data) {
    679    buf.writeUInt16BE(option.data.length, offset)
    680    offset += 2
    681    option.data.copy(buf, offset)
    682    offset += option.data.length
    683  } else {
    684    switch (code) {
    685      // case 3: NSID.  No encode makes sense.
    686      // case 5,6,7: Not implementable
    687      case 8: // ECS
    688        // note: do IP math before calling
    689        const spl = option.sourcePrefixLength || 0
    690        const fam = option.family || (ip.isV4Format(option.ip) ? 1 : 2)
    691        const ipBuf = ip.toBuffer(option.ip)
    692        const ipLen = Math.ceil(spl / 8)
    693        buf.writeUInt16BE(ipLen + 4, offset)
    694        offset += 2
    695        buf.writeUInt16BE(fam, offset)
    696        offset += 2
    697        buf.writeUInt8(spl, offset++)
    698        buf.writeUInt8(option.scopePrefixLength || 0, offset++)
    699 
    700        ipBuf.copy(buf, offset, 0, ipLen)
    701        offset += ipLen
    702        break
    703      // case 9: EXPIRE (experimental)
    704      // case 10: COOKIE.  No encode makes sense.
    705      case 11: // KEEP-ALIVE
    706        if (option.timeout) {
    707          buf.writeUInt16BE(2, offset)
    708          offset += 2
    709          buf.writeUInt16BE(option.timeout, offset)
    710          offset += 2
    711        } else {
    712          buf.writeUInt16BE(0, offset)
    713          offset += 2
    714        }
    715        break
    716      case 12: // PADDING
    717        const len = option.length || 0
    718        buf.writeUInt16BE(len, offset)
    719        offset += 2
    720        buf.fill(0, offset, offset + len)
    721        offset += len
    722        break
    723      // case 13:  CHAIN.  Experimental.
    724      case 14: // KEY-TAG
    725        const tagsLen = option.tags.length * 2
    726        buf.writeUInt16BE(tagsLen, offset)
    727        offset += 2
    728        for (const tag of option.tags) {
    729          buf.writeUInt16BE(tag, offset)
    730          offset += 2
    731        }
    732        break
    733      case 15: // EDNS_ERROR
    734        const text = option.text || "";
    735        buf.writeUInt16BE(text.length + 2, offset)
    736        offset += 2;
    737        buf.writeUInt16BE(option.extended_error, offset)
    738        offset += 2;
    739        buf.write(text, offset);
    740        offset += option.text.length;
    741        break;
    742      default:
    743        throw new Error(`Unknown roption code: ${option.code}`)
    744    }
    745  }
    746 
    747  roption.encode.bytes = offset - oldOffset
    748  return buf
    749 }
    750 
    751 roption.encode.bytes = 0
    752 
    753 roption.decode = function (buf, offset) {
    754  if (!offset) offset = 0
    755  const option = {}
    756  option.code = buf.readUInt16BE(offset)
    757  option.type = optioncodes.toString(option.code)
    758  offset += 2
    759  const len = buf.readUInt16BE(offset)
    760  offset += 2
    761  option.data = buf.slice(offset, offset + len)
    762  switch (option.code) {
    763    // case 3: NSID.  No decode makes sense.
    764    case 8: // ECS
    765      option.family = buf.readUInt16BE(offset)
    766      offset += 2
    767      option.sourcePrefixLength = buf.readUInt8(offset++)
    768      option.scopePrefixLength = buf.readUInt8(offset++)
    769      const padded = Buffer.alloc((option.family === 1) ? 4 : 16)
    770      buf.copy(padded, 0, offset, offset + len - 4)
    771      option.ip = ip.toString(padded)
    772      break
    773    // case 12: Padding.  No decode makes sense.
    774    case 11: // KEEP-ALIVE
    775      if (len > 0) {
    776        option.timeout = buf.readUInt16BE(offset)
    777        offset += 2
    778      }
    779      break
    780    case 14:
    781      option.tags = []
    782      for (let i = 0; i < len; i += 2) {
    783        option.tags.push(buf.readUInt16BE(offset))
    784        offset += 2
    785      }
    786    // don't worry about default.  caller will use data if desired
    787  }
    788 
    789  roption.decode.bytes = len + 4
    790  return option
    791 }
    792 
    793 roption.decode.bytes = 0
    794 
    795 roption.encodingLength = function (option) {
    796  if (option.data) {
    797    return option.data.length + 4
    798  }
    799  const code = optioncodes.toCode(option.code)
    800  switch (code) {
    801    case 8: // ECS
    802      const spl = option.sourcePrefixLength || 0
    803      return Math.ceil(spl / 8) + 8
    804    case 11: // KEEP-ALIVE
    805      return (typeof option.timeout === 'number') ? 6 : 4
    806    case 12: // PADDING
    807      return option.length + 4
    808    case 14: // KEY-TAG
    809      return 4 + (option.tags.length * 2)
    810    case 15: // EDNS_ERROR
    811      return 4 + 2 + option.text.length
    812  }
    813  throw new Error(`Unknown roption code: ${option.code}`)
    814 }
    815 
    816 const ropt = exports.opt = {}
    817 
    818 ropt.encode = function (options, buf, offset) {
    819  if (!buf) buf = Buffer.allocUnsafe(ropt.encodingLength(options))
    820  if (!offset) offset = 0
    821  const oldOffset = offset
    822 
    823  const rdlen = encodingLengthList(options, roption)
    824  buf.writeUInt16BE(rdlen, offset)
    825  offset = encodeList(options, roption, buf, offset + 2)
    826 
    827  ropt.encode.bytes = offset - oldOffset
    828  return buf
    829 }
    830 
    831 ropt.encode.bytes = 0
    832 
    833 ropt.decode = function (buf, offset) {
    834  if (!offset) offset = 0
    835  const oldOffset = offset
    836 
    837  const options = []
    838  let rdlen = buf.readUInt16BE(offset)
    839  offset += 2
    840  let o = 0
    841  while (rdlen > 0) {
    842    options[o++] = roption.decode(buf, offset)
    843    offset += roption.decode.bytes
    844    rdlen -= roption.decode.bytes
    845  }
    846  ropt.decode.bytes = offset - oldOffset
    847  return options
    848 }
    849 
    850 ropt.decode.bytes = 0
    851 
    852 ropt.encodingLength = function (options) {
    853  return 2 + encodingLengthList(options || [], roption)
    854 }
    855 
    856 const rdnskey = exports.dnskey = {}
    857 
    858 rdnskey.PROTOCOL_DNSSEC = 3
    859 rdnskey.ZONE_KEY = 0x80
    860 rdnskey.SECURE_ENTRYPOINT = 0x8000
    861 
    862 rdnskey.encode = function (key, buf, offset) {
    863  if (!buf) buf = Buffer.allocUnsafe(rdnskey.encodingLength(key))
    864  if (!offset) offset = 0
    865  const oldOffset = offset
    866 
    867  const keydata = key.key
    868  if (!Buffer.isBuffer(keydata)) {
    869    throw new Error('Key must be a Buffer')
    870  }
    871 
    872  offset += 2 // Leave space for length
    873  buf.writeUInt16BE(key.flags, offset)
    874  offset += 2
    875  buf.writeUInt8(rdnskey.PROTOCOL_DNSSEC, offset)
    876  offset += 1
    877  buf.writeUInt8(key.algorithm, offset)
    878  offset += 1
    879  keydata.copy(buf, offset, 0, keydata.length)
    880  offset += keydata.length
    881 
    882  rdnskey.encode.bytes = offset - oldOffset
    883  buf.writeUInt16BE(rdnskey.encode.bytes - 2, oldOffset)
    884  return buf
    885 }
    886 
    887 rdnskey.encode.bytes = 0
    888 
    889 rdnskey.decode = function (buf, offset) {
    890  if (!offset) offset = 0
    891  const oldOffset = offset
    892 
    893  var key = {}
    894  var length = buf.readUInt16BE(offset)
    895  offset += 2
    896  key.flags = buf.readUInt16BE(offset)
    897  offset += 2
    898  if (buf.readUInt8(offset) !== rdnskey.PROTOCOL_DNSSEC) {
    899    throw new Error('Protocol must be 3')
    900  }
    901  offset += 1
    902  key.algorithm = buf.readUInt8(offset)
    903  offset += 1
    904  key.key = buf.slice(offset, oldOffset + length + 2)
    905  offset += key.key.length
    906  rdnskey.decode.bytes = offset - oldOffset
    907  return key
    908 }
    909 
    910 rdnskey.decode.bytes = 0
    911 
    912 rdnskey.encodingLength = function (key) {
    913  return 6 + Buffer.byteLength(key.key)
    914 }
    915 
    916 const rrrsig = exports.rrsig = {}
    917 
    918 rrrsig.encode = function (sig, buf, offset) {
    919  if (!buf) buf = Buffer.allocUnsafe(rrrsig.encodingLength(sig))
    920  if (!offset) offset = 0
    921  const oldOffset = offset
    922 
    923  const signature = sig.signature
    924  if (!Buffer.isBuffer(signature)) {
    925    throw new Error('Signature must be a Buffer')
    926  }
    927 
    928  offset += 2 // Leave space for length
    929  buf.writeUInt16BE(types.toType(sig.typeCovered), offset)
    930  offset += 2
    931  buf.writeUInt8(sig.algorithm, offset)
    932  offset += 1
    933  buf.writeUInt8(sig.labels, offset)
    934  offset += 1
    935  buf.writeUInt32BE(sig.originalTTL, offset)
    936  offset += 4
    937  buf.writeUInt32BE(sig.expiration, offset)
    938  offset += 4
    939  buf.writeUInt32BE(sig.inception, offset)
    940  offset += 4
    941  buf.writeUInt16BE(sig.keyTag, offset)
    942  offset += 2
    943  name.encode(sig.signersName, buf, offset)
    944  offset += name.encode.bytes
    945  signature.copy(buf, offset, 0, signature.length)
    946  offset += signature.length
    947 
    948  rrrsig.encode.bytes = offset - oldOffset
    949  buf.writeUInt16BE(rrrsig.encode.bytes - 2, oldOffset)
    950  return buf
    951 }
    952 
    953 rrrsig.encode.bytes = 0
    954 
    955 rrrsig.decode = function (buf, offset) {
    956  if (!offset) offset = 0
    957  const oldOffset = offset
    958 
    959  var sig = {}
    960  var length = buf.readUInt16BE(offset)
    961  offset += 2
    962  sig.typeCovered = types.toString(buf.readUInt16BE(offset))
    963  offset += 2
    964  sig.algorithm = buf.readUInt8(offset)
    965  offset += 1
    966  sig.labels = buf.readUInt8(offset)
    967  offset += 1
    968  sig.originalTTL = buf.readUInt32BE(offset)
    969  offset += 4
    970  sig.expiration = buf.readUInt32BE(offset)
    971  offset += 4
    972  sig.inception = buf.readUInt32BE(offset)
    973  offset += 4
    974  sig.keyTag = buf.readUInt16BE(offset)
    975  offset += 2
    976  sig.signersName = name.decode(buf, offset)
    977  offset += name.decode.bytes
    978  sig.signature = buf.slice(offset, oldOffset + length + 2)
    979  offset += sig.signature.length
    980  rrrsig.decode.bytes = offset - oldOffset
    981  return sig
    982 }
    983 
    984 rrrsig.decode.bytes = 0
    985 
    986 rrrsig.encodingLength = function (sig) {
    987  return 20 +
    988    name.encodingLength(sig.signersName) +
    989    Buffer.byteLength(sig.signature)
    990 }
    991 
    992 const rrp = exports.rp = {}
    993 
    994 rrp.encode = function (data, buf, offset) {
    995  if (!buf) buf = Buffer.allocUnsafe(rrp.encodingLength(data))
    996  if (!offset) offset = 0
    997  const oldOffset = offset
    998 
    999  offset += 2 // Leave space for length
   1000  name.encode(data.mbox || '.', buf, offset)
   1001  offset += name.encode.bytes
   1002  name.encode(data.txt || '.', buf, offset)
   1003  offset += name.encode.bytes
   1004  rrp.encode.bytes = offset - oldOffset
   1005  buf.writeUInt16BE(rrp.encode.bytes - 2, oldOffset)
   1006  return buf
   1007 }
   1008 
   1009 rrp.encode.bytes = 0
   1010 
   1011 rrp.decode = function (buf, offset) {
   1012  if (!offset) offset = 0
   1013  const oldOffset = offset
   1014 
   1015  const data = {}
   1016  offset += 2
   1017  data.mbox = name.decode(buf, offset) || '.'
   1018  offset += name.decode.bytes
   1019  data.txt = name.decode(buf, offset) || '.'
   1020  offset += name.decode.bytes
   1021  rrp.decode.bytes = offset - oldOffset
   1022  return data
   1023 }
   1024 
   1025 rrp.decode.bytes = 0
   1026 
   1027 rrp.encodingLength = function (data) {
   1028  return 2 + name.encodingLength(data.mbox || '.') + name.encodingLength(data.txt || '.')
   1029 }
   1030 
   1031 const typebitmap = {}
   1032 
   1033 typebitmap.encode = function (typelist, buf, offset) {
   1034  if (!buf) buf = Buffer.allocUnsafe(typebitmap.encodingLength(typelist))
   1035  if (!offset) offset = 0
   1036  const oldOffset = offset
   1037 
   1038  var typesByWindow = []
   1039  for (var i = 0; i < typelist.length; i++) {
   1040    var typeid = types.toType(typelist[i])
   1041    if (typesByWindow[typeid >> 8] === undefined) {
   1042      typesByWindow[typeid >> 8] = []
   1043    }
   1044    typesByWindow[typeid >> 8][(typeid >> 3) & 0x1F] |= 1 << (7 - (typeid & 0x7))
   1045  }
   1046 
   1047  for (i = 0; i < typesByWindow.length; i++) {
   1048    if (typesByWindow[i] !== undefined) {
   1049      var windowBuf = Buffer.from(typesByWindow[i])
   1050      buf.writeUInt8(i, offset)
   1051      offset += 1
   1052      buf.writeUInt8(windowBuf.length, offset)
   1053      offset += 1
   1054      windowBuf.copy(buf, offset)
   1055      offset += windowBuf.length
   1056    }
   1057  }
   1058 
   1059  typebitmap.encode.bytes = offset - oldOffset
   1060  return buf
   1061 }
   1062 
   1063 typebitmap.encode.bytes = 0
   1064 
   1065 typebitmap.decode = function (buf, offset, length) {
   1066  if (!offset) offset = 0
   1067  const oldOffset = offset
   1068 
   1069  var typelist = []
   1070  while (offset - oldOffset < length) {
   1071    var window = buf.readUInt8(offset)
   1072    offset += 1
   1073    var windowLength = buf.readUInt8(offset)
   1074    offset += 1
   1075    for (var i = 0; i < windowLength; i++) {
   1076      var b = buf.readUInt8(offset + i)
   1077      for (var j = 0; j < 8; j++) {
   1078        if (b & (1 << (7 - j))) {
   1079          var typeid = types.toString((window << 8) | (i << 3) | j)
   1080          typelist.push(typeid)
   1081        }
   1082      }
   1083    }
   1084    offset += windowLength
   1085  }
   1086 
   1087  typebitmap.decode.bytes = offset - oldOffset
   1088  return typelist
   1089 }
   1090 
   1091 typebitmap.decode.bytes = 0
   1092 
   1093 typebitmap.encodingLength = function (typelist) {
   1094  var extents = []
   1095  for (var i = 0; i < typelist.length; i++) {
   1096    var typeid = types.toType(typelist[i])
   1097    extents[typeid >> 8] = Math.max(extents[typeid >> 8] || 0, typeid & 0xFF)
   1098  }
   1099 
   1100  var len = 0
   1101  for (i = 0; i < extents.length; i++) {
   1102    if (extents[i] !== undefined) {
   1103      len += 2 + Math.ceil((extents[i] + 1) / 8)
   1104    }
   1105  }
   1106 
   1107  return len
   1108 }
   1109 
   1110 const rnsec = exports.nsec = {}
   1111 
   1112 rnsec.encode = function (record, buf, offset) {
   1113  if (!buf) buf = Buffer.allocUnsafe(rnsec.encodingLength(record))
   1114  if (!offset) offset = 0
   1115  const oldOffset = offset
   1116 
   1117  offset += 2 // Leave space for length
   1118  name.encode(record.nextDomain, buf, offset)
   1119  offset += name.encode.bytes
   1120  typebitmap.encode(record.rrtypes, buf, offset)
   1121  offset += typebitmap.encode.bytes
   1122 
   1123  rnsec.encode.bytes = offset - oldOffset
   1124  buf.writeUInt16BE(rnsec.encode.bytes - 2, oldOffset)
   1125  return buf
   1126 }
   1127 
   1128 rnsec.encode.bytes = 0
   1129 
   1130 rnsec.decode = function (buf, offset) {
   1131  if (!offset) offset = 0
   1132  const oldOffset = offset
   1133 
   1134  var record = {}
   1135  var length = buf.readUInt16BE(offset)
   1136  offset += 2
   1137  record.nextDomain = name.decode(buf, offset)
   1138  offset += name.decode.bytes
   1139  record.rrtypes = typebitmap.decode(buf, offset, length - (offset - oldOffset))
   1140  offset += typebitmap.decode.bytes
   1141 
   1142  rnsec.decode.bytes = offset - oldOffset
   1143  return record
   1144 }
   1145 
   1146 rnsec.decode.bytes = 0
   1147 
   1148 rnsec.encodingLength = function (record) {
   1149  return 2 +
   1150    name.encodingLength(record.nextDomain) +
   1151    typebitmap.encodingLength(record.rrtypes)
   1152 }
   1153 
   1154 const rnsec3 = exports.nsec3 = {}
   1155 
   1156 rnsec3.encode = function (record, buf, offset) {
   1157  if (!buf) buf = Buffer.allocUnsafe(rnsec3.encodingLength(record))
   1158  if (!offset) offset = 0
   1159  const oldOffset = offset
   1160 
   1161  const salt = record.salt
   1162  if (!Buffer.isBuffer(salt)) {
   1163    throw new Error('salt must be a Buffer')
   1164  }
   1165 
   1166  const nextDomain = record.nextDomain
   1167  if (!Buffer.isBuffer(nextDomain)) {
   1168    throw new Error('nextDomain must be a Buffer')
   1169  }
   1170 
   1171  offset += 2 // Leave space for length
   1172  buf.writeUInt8(record.algorithm, offset)
   1173  offset += 1
   1174  buf.writeUInt8(record.flags, offset)
   1175  offset += 1
   1176  buf.writeUInt16BE(record.iterations, offset)
   1177  offset += 2
   1178  buf.writeUInt8(salt.length, offset)
   1179  offset += 1
   1180  salt.copy(buf, offset, 0, salt.length)
   1181  offset += salt.length
   1182  buf.writeUInt8(nextDomain.length, offset)
   1183  offset += 1
   1184  nextDomain.copy(buf, offset, 0, nextDomain.length)
   1185  offset += nextDomain.length
   1186  typebitmap.encode(record.rrtypes, buf, offset)
   1187  offset += typebitmap.encode.bytes
   1188 
   1189  rnsec3.encode.bytes = offset - oldOffset
   1190  buf.writeUInt16BE(rnsec3.encode.bytes - 2, oldOffset)
   1191  return buf
   1192 }
   1193 
   1194 rnsec3.encode.bytes = 0
   1195 
   1196 rnsec3.decode = function (buf, offset) {
   1197  if (!offset) offset = 0
   1198  const oldOffset = offset
   1199 
   1200  var record = {}
   1201  var length = buf.readUInt16BE(offset)
   1202  offset += 2
   1203  record.algorithm = buf.readUInt8(offset)
   1204  offset += 1
   1205  record.flags = buf.readUInt8(offset)
   1206  offset += 1
   1207  record.iterations = buf.readUInt16BE(offset)
   1208  offset += 2
   1209  const saltLength = buf.readUInt8(offset)
   1210  offset += 1
   1211  record.salt = buf.slice(offset, offset + saltLength)
   1212  offset += saltLength
   1213  const hashLength = buf.readUInt8(offset)
   1214  offset += 1
   1215  record.nextDomain = buf.slice(offset, offset + hashLength)
   1216  offset += hashLength
   1217  record.rrtypes = typebitmap.decode(buf, offset, length - (offset - oldOffset))
   1218  offset += typebitmap.decode.bytes
   1219 
   1220  rnsec3.decode.bytes = offset - oldOffset
   1221  return record
   1222 }
   1223 
   1224 rnsec3.decode.bytes = 0
   1225 
   1226 rnsec3.encodingLength = function (record) {
   1227  return 8 +
   1228    record.salt.length +
   1229    record.nextDomain.length +
   1230    typebitmap.encodingLength(record.rrtypes)
   1231 }
   1232 
   1233 const rds = exports.ds = {}
   1234 
   1235 rds.encode = function (digest, buf, offset) {
   1236  if (!buf) buf = Buffer.allocUnsafe(rds.encodingLength(digest))
   1237  if (!offset) offset = 0
   1238  const oldOffset = offset
   1239 
   1240  const digestdata = digest.digest
   1241  if (!Buffer.isBuffer(digestdata)) {
   1242    throw new Error('Digest must be a Buffer')
   1243  }
   1244 
   1245  offset += 2 // Leave space for length
   1246  buf.writeUInt16BE(digest.keyTag, offset)
   1247  offset += 2
   1248  buf.writeUInt8(digest.algorithm, offset)
   1249  offset += 1
   1250  buf.writeUInt8(digest.digestType, offset)
   1251  offset += 1
   1252  digestdata.copy(buf, offset, 0, digestdata.length)
   1253  offset += digestdata.length
   1254 
   1255  rds.encode.bytes = offset - oldOffset
   1256  buf.writeUInt16BE(rds.encode.bytes - 2, oldOffset)
   1257  return buf
   1258 }
   1259 
   1260 rds.encode.bytes = 0
   1261 
   1262 rds.decode = function (buf, offset) {
   1263  if (!offset) offset = 0
   1264  const oldOffset = offset
   1265 
   1266  var digest = {}
   1267  var length = buf.readUInt16BE(offset)
   1268  offset += 2
   1269  digest.keyTag = buf.readUInt16BE(offset)
   1270  offset += 2
   1271  digest.algorithm = buf.readUInt8(offset)
   1272  offset += 1
   1273  digest.digestType = buf.readUInt8(offset)
   1274  offset += 1
   1275  digest.digest = buf.slice(offset, oldOffset + length + 2)
   1276  offset += digest.digest.length
   1277  rds.decode.bytes = offset - oldOffset
   1278  return digest
   1279 }
   1280 
   1281 rds.decode.bytes = 0
   1282 
   1283 rds.encodingLength = function (digest) {
   1284  return 6 + Buffer.byteLength(digest.digest)
   1285 }
   1286 
   1287 const svcparam = exports.svcparam = {}
   1288 
   1289 svcparam.keyToNumber = function(keyName) {
   1290  switch (keyName.toLowerCase()) {
   1291    case 'mandatory': return 0
   1292    case 'alpn' : return 1
   1293    case 'no-default-alpn' : return 2
   1294    case 'port' : return 3
   1295    case 'ipv4hint' : return 4
   1296    case 'echconfig' : return 5
   1297    case 'ipv6hint' : return 6
   1298    case 'odoh' : return 32769
   1299    case 'key65535' : return 65535
   1300  }
   1301  if (!keyName.startsWith('key')) {
   1302    throw new Error(`Name must start with key: ${keyName}`);
   1303  }
   1304 
   1305  return Number.parseInt(keyName.substring(3));
   1306 }
   1307 
   1308 svcparam.numberToKeyName = function(number) {
   1309  switch (number) {
   1310    case 0 : return 'mandatory'
   1311    case 1 : return 'alpn'
   1312    case 2 : return 'no-default-alpn'
   1313    case 3 : return 'port'
   1314    case 4 : return 'ipv4hint'
   1315    case 5 : return 'echconfig'
   1316    case 6 : return 'ipv6hint'
   1317    case 32769 : return 'odoh'
   1318  }
   1319 
   1320  return `key${number}`;
   1321 }
   1322 
   1323 svcparam.encode = function(param, buf, offset) {
   1324  if (!buf) buf = Buffer.allocUnsafe(svcparam.encodingLength(param))
   1325  if (!offset) offset = 0
   1326 
   1327  let key = param.key;
   1328  if (typeof param.key !== 'number') {
   1329    key = svcparam.keyToNumber(param.key);
   1330  }
   1331 
   1332  buf.writeUInt16BE(key || 0, offset)
   1333  offset += 2;
   1334  svcparam.encode.bytes = 2;
   1335 
   1336  if (key == 0) { // mandatory
   1337    let values = param.value;
   1338    if (!Array.isArray(values)) values = [values];
   1339    buf.writeUInt16BE(values.length*2, offset);
   1340    offset += 2;
   1341    svcparam.encode.bytes += 2;
   1342 
   1343    for (let val of values) {
   1344      if (typeof val !== 'number') {
   1345        val = svcparam.keyToNumber(val);
   1346      }
   1347      buf.writeUInt16BE(val, offset);
   1348      offset += 2;
   1349      svcparam.encode.bytes += 2;
   1350    }
   1351  } else if (key == 1) { // alpn
   1352    let val = param.value;
   1353    if (!Array.isArray(val)) val = [val];
   1354    // The alpn param is prefixed by its length as a single byte, so the
   1355    // initialValue to reduce function is the length of the array.
   1356    let total = val.reduce(function(result, id) {
   1357      return result += id.length;
   1358    }, val.length);
   1359 
   1360    buf.writeUInt16BE(total, offset);
   1361    offset += 2;
   1362    svcparam.encode.bytes += 2;
   1363 
   1364    for (let id of val) {
   1365      buf.writeUInt8(id.length, offset);
   1366      offset += 1;
   1367      svcparam.encode.bytes += 1;
   1368 
   1369      buf.write(id, offset);
   1370      offset += id.length;
   1371      svcparam.encode.bytes += id.length;
   1372    }
   1373  } else if (key == 2) { // no-default-alpn
   1374    buf.writeUInt16BE(0, offset);
   1375    offset += 2;
   1376    svcparam.encode.bytes += 2;
   1377  } else if (key == 3) { // port
   1378    buf.writeUInt16BE(2, offset);
   1379    offset += 2;
   1380    svcparam.encode.bytes += 2;
   1381    buf.writeUInt16BE(param.value || 0, offset);
   1382    offset += 2;
   1383    svcparam.encode.bytes += 2;
   1384  } else if (key == 4) { //ipv4hint
   1385    let val = param.value;
   1386    if (!Array.isArray(val)) val = [val];
   1387    buf.writeUInt16BE(val.length*4, offset);
   1388    offset += 2;
   1389    svcparam.encode.bytes += 2;
   1390 
   1391    for (let host of val) {
   1392      ip.toBuffer(host, buf, offset)
   1393      offset += 4;
   1394      svcparam.encode.bytes += 4;
   1395    }
   1396  } else if (key == 5) { //echconfig
   1397    if (svcparam.ech) {
   1398      buf.writeUInt16BE(svcparam.ech.length, offset);
   1399      offset += 2;
   1400      svcparam.encode.bytes += 2;
   1401      for (let i = 0; i < svcparam.ech.length; i++) {
   1402        buf.writeUInt8(svcparam.ech[i], offset);
   1403        offset++;
   1404      }
   1405      svcparam.encode.bytes += svcparam.ech.length;
   1406    } else {
   1407      buf.writeUInt16BE(param.value.length, offset);
   1408      offset += 2;
   1409      svcparam.encode.bytes += 2;
   1410      buf.write(param.value, offset);
   1411      offset += param.value.length;
   1412      svcparam.encode.bytes += param.value.length;
   1413    }
   1414  } else if (key == 6) { //ipv6hint
   1415    let val = param.value;
   1416    if (!Array.isArray(val)) val = [val];
   1417    buf.writeUInt16BE(val.length*16, offset);
   1418    offset += 2;
   1419    svcparam.encode.bytes += 2;
   1420 
   1421    for (let host of val) {
   1422      ip.toBuffer(host, buf, offset)
   1423      offset += 16;
   1424      svcparam.encode.bytes += 16;
   1425    }
   1426   } else if (key == 32769) { //odoh
   1427      if (svcparam.odoh) {
   1428        buf.writeUInt16BE(svcparam.odoh.length, offset);
   1429        offset += 2;
   1430        svcparam.encode.bytes += 2;
   1431        for (let i = 0; i < svcparam.odoh.length; i++) {
   1432          buf.writeUInt8(svcparam.odoh[i], offset);
   1433          offset++;
   1434        }
   1435        svcparam.encode.bytes += svcparam.odoh.length;
   1436        svcparam.odoh = null;
   1437      } else {
   1438        buf.writeUInt16BE(param.value.length, offset);
   1439        offset += 2;
   1440        svcparam.encode.bytes += 2;
   1441        buf.write(param.value, offset);
   1442        offset += param.value.length;
   1443        svcparam.encode.bytes += param.value.length;
   1444      }
   1445  } else {
   1446    // Unknown option
   1447    buf.writeUInt16BE(0, offset); // 0 length since we don't know how to encode
   1448    offset += 2;
   1449    svcparam.encode.bytes += 2;
   1450  }
   1451 
   1452 }
   1453 
   1454 svcparam.encode.bytes = 0;
   1455 
   1456 svcparam.decode = function (buf, offset) {
   1457  let param = {};
   1458  let id = buf.readUInt16BE(offset);
   1459  param.key = svcparam.numberToKeyName(id);
   1460  offset += 2;
   1461  svcparam.decode.bytes = 2;
   1462 
   1463  let len = buf.readUInt16BE(offset);
   1464  offset += 2;
   1465  svcparam.decode.bytes += 2;
   1466 
   1467  param.value = buf.toString('utf-8', offset, offset + len);
   1468  offset += len;
   1469  svcparam.decode.bytes += len;
   1470 
   1471  return param;
   1472 }
   1473 
   1474 svcparam.decode.bytes = 0;
   1475 
   1476 svcparam.encodingLength = function (param) {
   1477  // 2 bytes for type, 2 bytes for length, what's left for the value
   1478 
   1479  switch (param.key) {
   1480    case 'mandatory' : return 4 + 2*(Array.isArray(param.value) ? param.value.length : 1)
   1481    case 'alpn' : {
   1482      let val = param.value;
   1483      if (!Array.isArray(val)) val = [val];
   1484      let total = val.reduce(function(result, id) {
   1485        return result += id.length;
   1486      }, val.length);
   1487      return 4 + total;
   1488    }
   1489    case 'no-default-alpn' : return 4
   1490    case 'port' : return 4 + 2
   1491    case 'ipv4hint' : return 4 + 4 * (Array.isArray(param.value) ? param.value.length : 1)
   1492    case 'echconfig' : {
   1493      if (param.needBase64Decode) {
   1494        svcparam.ech = Buffer.from(param.value, "base64");
   1495        return 4 + svcparam.ech.length;
   1496      }
   1497      return 4 + param.value.length
   1498    }
   1499    case 'ipv6hint' : return 4 + 16 * (Array.isArray(param.value) ? param.value.length : 1)
   1500    case 'odoh' : {
   1501      if (param.needBase64Decode) {
   1502        svcparam.odoh = Buffer.from(param.value, "base64");
   1503        return 4 + svcparam.odoh.length;
   1504      }
   1505      return 4 + param.value.length
   1506    }
   1507    case 'key65535' : return 4
   1508    default: return 4 // unknown option
   1509  }
   1510 }
   1511 
   1512 const rhttpssvc = exports.httpssvc = {}
   1513 
   1514 rhttpssvc.encode = function(data, buf, offset) {
   1515  if (!buf) buf = Buffer.allocUnsafe(rhttpssvc.encodingLength(data))
   1516  if (!offset) offset = 0
   1517 
   1518  buf.writeUInt16BE(rhttpssvc.encodingLength(data) - 2 , offset);
   1519  offset += 2;
   1520 
   1521  buf.writeUInt16BE(data.priority || 0, offset);
   1522  rhttpssvc.encode.bytes = 4;
   1523  offset += 2;
   1524  name.encode(data.name, buf, offset);
   1525  rhttpssvc.encode.bytes += name.encode.bytes;
   1526  offset += name.encode.bytes;
   1527 
   1528  if (data.priority == 0) {
   1529    return;
   1530  }
   1531 
   1532  for (let val of data.values) {
   1533    svcparam.encode(val, buf, offset);
   1534    offset += svcparam.encode.bytes;
   1535    rhttpssvc.encode.bytes += svcparam.encode.bytes;
   1536  }
   1537 
   1538  return buf;
   1539 }
   1540 
   1541 rhttpssvc.encode.bytes = 0;
   1542 
   1543 rhttpssvc.decode = function (buf, offset) {
   1544  let rdlen = buf.readUInt16BE(offset);
   1545  let oldOffset = offset;
   1546  offset += 2;
   1547  let record = {}
   1548  record.priority = buf.readUInt16BE(offset);
   1549  offset += 2;
   1550  rhttpssvc.decode.bytes = 4;
   1551  record.name = name.decode(buf, offset);
   1552  offset += name.decode.bytes;
   1553  rhttpssvc.decode.bytes += name.decode.bytes;
   1554 
   1555  while (rdlen > rhttpssvc.decode.bytes - 2) {
   1556    let rec1 = svcparam.decode(buf, offset);
   1557    offset += svcparam.decode.bytes;
   1558    rhttpssvc.decode.bytes += svcparam.decode.bytes;
   1559    record.values.push(rec1);
   1560  }
   1561 
   1562  return record;
   1563 }
   1564 
   1565 rhttpssvc.decode.bytes = 0;
   1566 
   1567 rhttpssvc.encodingLength = function (data) {
   1568  let len =
   1569    2 + // rdlen
   1570    2 + // priority
   1571    name.encodingLength(data.name);
   1572  len += data.values.map(svcparam.encodingLength).reduce((acc, len) => acc + len, 0);
   1573  return len;
   1574 }
   1575 
   1576 const renc = exports.record = function (type) {
   1577  switch (type.toUpperCase()) {
   1578    case 'A': return ra
   1579    case 'PTR': return rptr
   1580    case 'CNAME': return rcname
   1581    case 'DNAME': return rdname
   1582    case 'TXT': return rtxt
   1583    case 'NULL': return rnull
   1584    case 'AAAA': return raaaa
   1585    case 'SRV': return rsrv
   1586    case 'HINFO': return rhinfo
   1587    case 'CAA': return rcaa
   1588    case 'NS': return rns
   1589    case 'SOA': return rsoa
   1590    case 'MX': return rmx
   1591    case 'OPT': return ropt
   1592    case 'DNSKEY': return rdnskey
   1593    case 'RRSIG': return rrrsig
   1594    case 'RP': return rrp
   1595    case 'NSEC': return rnsec
   1596    case 'NSEC3': return rnsec3
   1597    case 'DS': return rds
   1598    case 'HTTPS': return rhttpssvc
   1599  }
   1600  return runknown
   1601 }
   1602 
   1603 const answer = exports.answer = {}
   1604 
   1605 answer.encode = function (a, buf, offset) {
   1606  if (!buf) buf = Buffer.allocUnsafe(answer.encodingLength(a))
   1607  if (!offset) offset = 0
   1608 
   1609  const oldOffset = offset
   1610 
   1611  name.encode(a.name, buf, offset)
   1612  offset += name.encode.bytes
   1613 
   1614  buf.writeUInt16BE(types.toType(a.type), offset)
   1615 
   1616  if (a.type.toUpperCase() === 'OPT') {
   1617    if (a.name !== '.') {
   1618      throw new Error('OPT name must be root.')
   1619    }
   1620    buf.writeUInt16BE(a.udpPayloadSize || 4096, offset + 2)
   1621    buf.writeUInt8(a.extendedRcode || 0, offset + 4)
   1622    buf.writeUInt8(a.ednsVersion || 0, offset + 5)
   1623    buf.writeUInt16BE(a.flags || 0, offset + 6)
   1624 
   1625    offset += 8
   1626    ropt.encode(a.options || [], buf, offset)
   1627    offset += ropt.encode.bytes
   1628  } else {
   1629    let klass = classes.toClass(a.class === undefined ? 'IN' : a.class)
   1630    if (a.flush) klass |= FLUSH_MASK // the 1st bit of the class is the flush bit
   1631    buf.writeUInt16BE(klass, offset + 2)
   1632    buf.writeUInt32BE(a.ttl || 0, offset + 4)
   1633 
   1634    offset += 8
   1635    const enc = renc(a.type)
   1636    enc.encode(a.data, buf, offset)
   1637    offset += enc.encode.bytes
   1638  }
   1639 
   1640  answer.encode.bytes = offset - oldOffset
   1641  return buf
   1642 }
   1643 
   1644 answer.encode.bytes = 0
   1645 
   1646 answer.decode = function (buf, offset) {
   1647  if (!offset) offset = 0
   1648 
   1649  const a = {}
   1650  const oldOffset = offset
   1651 
   1652  a.name = name.decode(buf, offset)
   1653  offset += name.decode.bytes
   1654  a.type = types.toString(buf.readUInt16BE(offset))
   1655  if (a.type === 'OPT') {
   1656    a.udpPayloadSize = buf.readUInt16BE(offset + 2)
   1657    a.extendedRcode = buf.readUInt8(offset + 4)
   1658    a.ednsVersion = buf.readUInt8(offset + 5)
   1659    a.flags = buf.readUInt16BE(offset + 6)
   1660    a.flag_do = ((a.flags >> 15) & 0x1) === 1
   1661    a.options = ropt.decode(buf, offset + 8)
   1662    offset += 8 + ropt.decode.bytes
   1663  } else {
   1664    const klass = buf.readUInt16BE(offset + 2)
   1665    a.ttl = buf.readUInt32BE(offset + 4)
   1666    a.class = classes.toString(klass & NOT_FLUSH_MASK)
   1667    a.flush = !!(klass & FLUSH_MASK)
   1668 
   1669    const enc = renc(a.type)
   1670    a.data = enc.decode(buf, offset + 8)
   1671    offset += 8 + enc.decode.bytes
   1672  }
   1673 
   1674  answer.decode.bytes = offset - oldOffset
   1675  return a
   1676 }
   1677 
   1678 answer.decode.bytes = 0
   1679 
   1680 answer.encodingLength = function (a) {
   1681  const data = (a.data !== null && a.data !== undefined) ? a.data : a.options
   1682  return name.encodingLength(a.name) + 8 + renc(a.type).encodingLength(data)
   1683 }
   1684 
   1685 const question = exports.question = {}
   1686 
   1687 question.encode = function (q, buf, offset) {
   1688  if (!buf) buf = Buffer.allocUnsafe(question.encodingLength(q))
   1689  if (!offset) offset = 0
   1690 
   1691  const oldOffset = offset
   1692 
   1693  name.encode(q.name, buf, offset)
   1694  offset += name.encode.bytes
   1695 
   1696  buf.writeUInt16BE(types.toType(q.type), offset)
   1697  offset += 2
   1698 
   1699  buf.writeUInt16BE(classes.toClass(q.class === undefined ? 'IN' : q.class), offset)
   1700  offset += 2
   1701 
   1702  question.encode.bytes = offset - oldOffset
   1703  return q
   1704 }
   1705 
   1706 question.encode.bytes = 0
   1707 
   1708 question.decode = function (buf, offset) {
   1709  if (!offset) offset = 0
   1710 
   1711  const oldOffset = offset
   1712  const q = {}
   1713 
   1714  q.name = name.decode(buf, offset)
   1715  offset += name.decode.bytes
   1716 
   1717  q.type = types.toString(buf.readUInt16BE(offset))
   1718  offset += 2
   1719 
   1720  q.class = classes.toString(buf.readUInt16BE(offset))
   1721  offset += 2
   1722 
   1723  const qu = !!(q.class & QU_MASK)
   1724  if (qu) q.class &= NOT_QU_MASK
   1725 
   1726  question.decode.bytes = offset - oldOffset
   1727  return q
   1728 }
   1729 
   1730 question.decode.bytes = 0
   1731 
   1732 question.encodingLength = function (q) {
   1733  return name.encodingLength(q.name) + 4
   1734 }
   1735 
   1736 exports.AUTHORITATIVE_ANSWER = 1 << 10
   1737 exports.TRUNCATED_RESPONSE = 1 << 9
   1738 exports.RECURSION_DESIRED = 1 << 8
   1739 exports.RECURSION_AVAILABLE = 1 << 7
   1740 exports.AUTHENTIC_DATA = 1 << 5
   1741 exports.CHECKING_DISABLED = 1 << 4
   1742 exports.DNSSEC_OK = 1 << 15
   1743 
   1744 exports.encode = function (result, buf, offset) {
   1745  if (!buf) buf = Buffer.allocUnsafe(exports.encodingLength(result))
   1746  if (!offset) offset = 0
   1747 
   1748  const oldOffset = offset
   1749 
   1750  if (!result.questions) result.questions = []
   1751  if (!result.answers) result.answers = []
   1752  if (!result.authorities) result.authorities = []
   1753  if (!result.additionals) result.additionals = []
   1754 
   1755  header.encode(result, buf, offset)
   1756  offset += header.encode.bytes
   1757 
   1758  offset = encodeList(result.questions, question, buf, offset)
   1759  offset = encodeList(result.answers, answer, buf, offset)
   1760  offset = encodeList(result.authorities, answer, buf, offset)
   1761  offset = encodeList(result.additionals, answer, buf, offset)
   1762 
   1763  exports.encode.bytes = offset - oldOffset
   1764 
   1765  return buf
   1766 }
   1767 
   1768 exports.encode.bytes = 0
   1769 
   1770 exports.decode = function (buf, offset) {
   1771  if (!offset) offset = 0
   1772 
   1773  const oldOffset = offset
   1774  const result = header.decode(buf, offset)
   1775  offset += header.decode.bytes
   1776 
   1777  offset = decodeList(result.questions, question, buf, offset)
   1778  offset = decodeList(result.answers, answer, buf, offset)
   1779  offset = decodeList(result.authorities, answer, buf, offset)
   1780  offset = decodeList(result.additionals, answer, buf, offset)
   1781 
   1782  exports.decode.bytes = offset - oldOffset
   1783 
   1784  return result
   1785 }
   1786 
   1787 exports.decode.bytes = 0
   1788 
   1789 exports.encodingLength = function (result) {
   1790  return header.encodingLength(result) +
   1791    encodingLengthList(result.questions || [], question) +
   1792    encodingLengthList(result.answers || [], answer) +
   1793    encodingLengthList(result.authorities || [], answer) +
   1794    encodingLengthList(result.additionals || [], answer)
   1795 }
   1796 
   1797 exports.streamEncode = function (result) {
   1798  const buf = exports.encode(result)
   1799  const sbuf = Buffer.allocUnsafe(2)
   1800  sbuf.writeUInt16BE(buf.byteLength)
   1801  const combine = Buffer.concat([sbuf, buf])
   1802  exports.streamEncode.bytes = combine.byteLength
   1803  return combine
   1804 }
   1805 
   1806 exports.streamEncode.bytes = 0
   1807 
   1808 exports.streamDecode = function (sbuf) {
   1809  const len = sbuf.readUInt16BE(0)
   1810  if (sbuf.byteLength < len + 2) {
   1811    // not enough data
   1812    return null
   1813  }
   1814  const result = exports.decode(sbuf.slice(2))
   1815  exports.streamDecode.bytes = exports.decode.bytes
   1816  return result
   1817 }
   1818 
   1819 exports.streamDecode.bytes = 0
   1820 
   1821 function encodingLengthList (list, enc) {
   1822  let len = 0
   1823  for (let i = 0; i < list.length; i++) len += enc.encodingLength(list[i])
   1824  return len
   1825 }
   1826 
   1827 function encodeList (list, enc, buf, offset) {
   1828  for (let i = 0; i < list.length; i++) {
   1829    enc.encode(list[i], buf, offset)
   1830    offset += enc.encode.bytes
   1831  }
   1832  return offset
   1833 }
   1834 
   1835 function decodeList (list, enc, buf, offset) {
   1836  for (let i = 0; i < list.length; i++) {
   1837    list[i] = enc.decode(buf, offset)
   1838    offset += enc.decode.bytes
   1839  }
   1840  return offset
   1841 }