lookup.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. const { create, parse } = require('dns.js')
  2. const { udp, net } = just
  3. const { loop } = just.factory
  4. const { readFile, isFile } = require('fs')
  5. const dnsServer = just.env().DNS_SERVER || '127.0.0.11'
  6. function parseLine (line) {
  7. const parts = line.split(/\s+/)
  8. const [address, ...hosts] = parts
  9. return { address, hosts }
  10. }
  11. const rxipv4 = /\d+\.\d+\.\d+\.\d+/
  12. const rxComment = /(\s+)?#.+/
  13. const rxName = /nameserver\s+(.+)/
  14. function readHosts () {
  15. const ipv4 = {}
  16. const ipv6 = {}
  17. const fileName = '/etc/hosts'
  18. if (!isFile(fileName)) {
  19. just.error(`${fileName} not found`)
  20. return { ipv4, ipv6 }
  21. }
  22. const hosts = readFile(fileName)
  23. just.error(`${fileName}:\n${hosts}`)
  24. const lines = hosts.split('\n').filter(line => line.trim())
  25. for (const line of lines) {
  26. if (line.match(rxComment)) continue
  27. const { address, hosts } = parseLine(line)
  28. if (address.match(rxipv4)) {
  29. for (const host of hosts) {
  30. ipv4[host] = address
  31. }
  32. } else {
  33. for (const host of hosts) {
  34. ipv6[host] = address
  35. }
  36. }
  37. }
  38. return { ipv4, ipv6 }
  39. }
  40. function lookupHosts (hostname) {
  41. const { ipv4 } = readHosts()
  42. return ipv4[hostname]
  43. }
  44. function readResolv () {
  45. const fileName = '/etc/resolv.conf'
  46. const results = []
  47. if (!isFile(fileName)) {
  48. just.error(`${fileName} not found`)
  49. return results
  50. }
  51. const resolv = readFile(fileName)
  52. just.error(`${fileName}:\n${resolv}`)
  53. const lines = resolv.split('\n').filter(line => line.trim())
  54. for (const line of lines) {
  55. const match = line.match(rxName)
  56. if (match && match.length > 1) {
  57. const [, ip] = match
  58. if (ip.match(rxipv4)) {
  59. results.push(ip)
  60. }
  61. }
  62. }
  63. return results
  64. }
  65. function lookup (query = 'www.google.com', onRecord = () => {}, address = dnsServer, port = 53, buf = new ArrayBuffer(65536)) {
  66. const ip = lookupHosts(query)
  67. if (ip) {
  68. just.error(`found ${ip} for ${query} in /etc/hosts`)
  69. onRecord(null, ip)
  70. return
  71. }
  72. const ips = readResolv()
  73. if (ips.length) {
  74. address = ips[0]
  75. just.error(`dns server ${address} found in /etc/resolv.conf`)
  76. }
  77. const fd = net.socket(net.AF_INET, net.SOCK_DGRAM | net.SOCK_NONBLOCK, 0)
  78. net.bind(fd, address, port)
  79. loop.add(fd, (fd, event) => {
  80. just.clearTimeout(timer)
  81. const answer = []
  82. const len = udp.recvmsg(fd, buf, answer)
  83. if (len <= 0) {
  84. onRecord(new Error('Bad Message Length'))
  85. return
  86. }
  87. const message = parse(buf, len)
  88. if (!message.answer.length) {
  89. onRecord(new Error(`Address Not Found for ${query}`))
  90. return
  91. }
  92. const { ip } = message.answer[0]
  93. const result = `${ip[0]}.${ip[1]}.${ip[2]}.${ip[3]}`
  94. just.error(`got ${result} for ${query} from ${address}`)
  95. loop.remove(fd)
  96. net.close(fd)
  97. onRecord(null, result)
  98. })
  99. const len = create(query, buf, 1)
  100. const rc = udp.sendmsg(fd, buf, address, port, len)
  101. if (rc === -1) {
  102. const errno = just.sys.errno()
  103. onRecord(new Error(`Error sending ${query} to ${address}: ${just.sys.strerror(errno)} (${errno})`))
  104. loop.remove(fd)
  105. net.close(fd)
  106. return
  107. }
  108. const timer = just.setTimeout(() => {
  109. onRecord(new Error(`Request timed out for ${query} at ${address}`))
  110. loop.remove(fd)
  111. net.close(fd)
  112. }, 1000)
  113. }
  114. module.exports = { lookup }