lookup.js 3.0 KB

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