dns.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. const opcode = {
  2. QUERY: 0,
  3. IQUERY: 1,
  4. STATUS: 2
  5. }
  6. const qtype = {
  7. A: 1,
  8. NS: 2,
  9. MD: 3,
  10. MF: 4,
  11. CNAME: 5,
  12. SOA: 6,
  13. MB: 7,
  14. MG: 8,
  15. MR: 9,
  16. NULL: 10,
  17. WKS: 11,
  18. PTR: 12,
  19. HINFO: 13,
  20. MINFO: 14,
  21. MX: 15,
  22. TXT: 16,
  23. // Additional
  24. AXFR: 252,
  25. MAILB: 253,
  26. MAILA: 254,
  27. ANY: 255
  28. }
  29. const qclass = {
  30. IN: 1,
  31. CS: 2,
  32. CH: 3,
  33. HS: 4,
  34. ANY: 255
  35. }
  36. const rcode = {
  37. NOERROR: 0,
  38. FORMAT: 1,
  39. SERVER: 2,
  40. NAME: 3,
  41. NOTIMPL: 4,
  42. REFUSED: 5
  43. }
  44. const types = { opcode, qtype, qclass, rcode }
  45. function readName (offset, buf, view) {
  46. let name = []
  47. let qnameSize = view.getUint8(offset++)
  48. while (qnameSize) {
  49. if ((qnameSize & 192) === 192) {
  50. let off = (qnameSize - 192) << 8
  51. off += view.getUint8(offset++)
  52. name = name.concat(readName(off, buf, view))
  53. qnameSize = 0
  54. } else {
  55. name.push(buf.readString(qnameSize, offset))
  56. offset += qnameSize
  57. qnameSize = view.getUint8(offset++)
  58. }
  59. }
  60. return name
  61. }
  62. const parse = (buf, len) => {
  63. const bytes = new Uint8Array(buf)
  64. const view = new DataView(buf)
  65. const id = view.getUint16(0)
  66. const flags = view.getUint16(2)
  67. const QR = (flags >> 15) & 0b1
  68. const opCode = (flags >> 11) & 0b1111
  69. const AA = (flags >> 10) & 0b1
  70. const TC = (flags >> 9) & 0b1
  71. const RD = (flags >> 8) & 0b1
  72. const RA = (flags >> 7) & 0b1
  73. const Z = (flags >> 4) & 0b111
  74. const RCODE = flags & 0b1111
  75. const qcount = view.getUint16(4)
  76. const ancount = view.getUint16(6)
  77. const nscount = view.getUint16(8)
  78. const arcount = view.getUint16(10)
  79. const question = []
  80. const answer = []
  81. const authority = []
  82. const additional = []
  83. const start = 12
  84. let off = start
  85. let i = off
  86. let counter = qcount
  87. while (counter--) {
  88. let size = 0
  89. const sections = []
  90. while (bytes[i++]) size++
  91. if (size > 0) {
  92. while (off - start < size) {
  93. const qnameSize = view.getUint8(off++)
  94. sections.push(buf.readString(qnameSize, off))
  95. off += qnameSize
  96. }
  97. }
  98. off++
  99. const qtype = view.getUint16(off)
  100. off += 2
  101. const qclass = view.getUint16(off)
  102. off += 2
  103. question.push({ qtype, qclass, name: sections })
  104. }
  105. counter = ancount
  106. while (counter--) {
  107. const next = view.getUint16(off)
  108. let name
  109. if ((0b1100000000000000 & next) === 0b1100000000000000) {
  110. name = readName(next & 0b11111111111111, buf, view)
  111. off += 2
  112. } else {
  113. name = readName(off, buf, view)
  114. off += name.length + (name.reduce((a, v) => a + v.length, 0)) + 1
  115. }
  116. const qtype = view.getUint16(off)
  117. off += 2
  118. const qclass = view.getUint16(off)
  119. off += 2
  120. const ttl = view.getUint32(off)
  121. off += 4
  122. const rdLength = view.getUint16(off)
  123. off += 2
  124. if (qtype === 5) {
  125. const cname = readName(off, buf, view)
  126. answer.push({ name, cname, qtype, qclass, ttl })
  127. } else if (qtype === 1) {
  128. answer.push({ name, qtype, qclass, ttl, ip: bytes.slice(off, off + rdLength) })
  129. }
  130. off += rdLength
  131. }
  132. return { bytes: bytes.slice(0, len), qcount, nscount, ancount, arcount, id, flags, QR, opCode, AA, TC, RD, RA, Z, RCODE, question, answer, authority, additional }
  133. }
  134. const create = (domain, buf, id, qtype = 1, qclass = 1) => {
  135. const view = new DataView(buf)
  136. const bytes = new Uint8Array(buf)
  137. view.setUint16(0, id)
  138. view.setUint16(2, 0b0000000101000000)
  139. view.setUint16(4, 1)
  140. view.setUint16(6, 0)
  141. view.setUint16(8, 0)
  142. view.setUint16(10, 0)
  143. let off = 12
  144. const parts = domain.split('.')
  145. for (const part of parts) {
  146. view.setUint8(off++, part.length)
  147. buf.writeString(part, off)
  148. off += part.length
  149. }
  150. bytes[off++] = 0
  151. view.setUint16(off, qtype)
  152. off += 2
  153. view.setUint16(off, qclass)
  154. off += 2
  155. return off
  156. }
  157. const qtypes = {}
  158. Object.keys(types.qtype).forEach(k => {
  159. qtypes[types.qtype[k]] = k
  160. })
  161. const qclasses = {}
  162. Object.keys(types.qclass).forEach(k => {
  163. qclasses[types.qclass[k]] = k
  164. })
  165. const opcodes = {}
  166. Object.keys(types.opcode).forEach(k => {
  167. opcodes[types.opcode[k]] = k
  168. })
  169. const rcodes = {}
  170. Object.keys(types.rcode).forEach(k => {
  171. rcodes[types.rcode[k]] = k
  172. })
  173. function getFlags (message) {
  174. const flags = []
  175. if (message.QR) flags.push('qr')
  176. if (message.AA) flags.push('aa')
  177. if (message.TC) flags.push('tc')
  178. if (message.RD) flags.push('rd')
  179. if (message.RA) flags.push('ra')
  180. if (message.Z) flags.push('z')
  181. return flags.join(' ')
  182. }
  183. module.exports = { getFlags, create, parse, types, qtypes, qclasses, opcodes, rcodes }