├── README.md ├── dns-resolver-async.js ├── dns-resolver-utility.js └── package.json /README.md: -------------------------------------------------------------------------------- 1 | # DNS-Resolver-Nodejs 2 | ## This project tries to implement the DNS Recursive Resolver in NodeJS. No external modules or dependencies is used. 3 | 4 | ## How to run the script? 5 | 6 | ```bash 7 | # Example installation steps 8 | git clone https://github.com/vishalg8454/DNS-Resolver-Nodejs.git 9 | cd DNS-Resolver-Nodejs 10 | node dns-resolver-async.js www.example.com 11 | ``` 12 | 13 | ## Sample Output for www.example.com 14 | ```bash 15 | Resolving DNS for www.example.com at 198.41.0.4 16 | Authority: 13 Additional: 14 Answer: 0 17 | Using Authoritaive nameserver: a.gtld-servers.net 18 | 19 | Resolving DNS for www.example.com at 192.5.6.30 20 | Authority: 2 Additional: 0 Answer: 0 21 | Using Authoritaive nameserver: a.iana-servers.net 22 | 23 | Resolving DNS for www.example.com at 199.43.135.53 24 | Authority: 0 Additional: 0 Answer: 1 25 | 26 | FOUND! 27 | Decoded name: www.example.com. 28 | IP Address: 93.184.216.34 29 | ``` 30 | Note: 198.41.0.4 is hardcoded as the root-server. You can try different values listed here https://www.iana.org/domains/root/servers 31 | -------------------------------------------------------------------------------- /dns-resolver-async.js: -------------------------------------------------------------------------------- 1 | import dgram from "dgram"; 2 | import { resolveDNS as x } from "./dns-resolver-utility.js"; 3 | 4 | const rootServer = "198.41.0.4"; 5 | 6 | function encodeURL(str) { 7 | const temp = 8 | str 9 | .split(".") 10 | .map( 11 | (s) => 12 | s.length.toString(16).padStart(2, 0) + 13 | s 14 | .split("") 15 | .map((c) => c.charCodeAt(0).toString(16).padStart(2, 0)) 16 | .join("") 17 | ) 18 | .join("") + "00"; 19 | 20 | return temp; 21 | } 22 | 23 | let ms = ""; 24 | 25 | function decodeDomain(str) { 26 | let ans = ""; 27 | const octet = str.substring(0, 2); 28 | const decimal = parseInt(octet, 16); 29 | const isPointer = decimal & 192; //checking if first 2 bits are set 30 | if (octet === "00") { 31 | return ""; 32 | } 33 | if (isPointer) { 34 | const doubleOctet = str.substring(0, 4); 35 | const mask = 16383; 36 | const doubleDecimal = parseInt(doubleOctet, 16); 37 | const offset = doubleDecimal & mask; 38 | ans += decodeDomain(ms.substring(offset * 2)); 39 | } else { 40 | //it is sequence of labels 41 | let ptr = 2; 42 | let local = ""; 43 | for (let i = 0; i < decimal; i++) { 44 | const temp = str.substring(ptr, ptr + 2); 45 | const ascii = parseInt(temp, 16); 46 | local += String.fromCharCode(ascii); 47 | ptr += 2; 48 | } 49 | ans += local + "." + decodeDomain(str.substring(ptr)); 50 | } 51 | return ans; 52 | } 53 | 54 | function decodeARecord(str) { 55 | let ans = ""; 56 | for (let i = 0; i < str.length; i += 2) { 57 | const temp = str.substring(i, i + 2); 58 | const ascii = parseInt(temp, 16); 59 | ans += ascii; 60 | if (i < str.length - 2) { 61 | ans += "."; 62 | } 63 | } 64 | return ans; 65 | } 66 | 67 | async function resolveDNS(hostname, serverAddress) { 68 | return new Promise((resolve, reject) => { 69 | const client = dgram.createSocket("udp4"); 70 | console.log("Resolving DNS for ", hostname, "at ", serverAddress); 71 | const hexString = 72 | "001600000001000000000000" + encodeURL(hostname) + "00010001"; 73 | 74 | const messageBuffer = Buffer.from(hexString, "hex"); 75 | const serverPort = 53; // Replace with the port of your UDP server 76 | 77 | client.send( 78 | messageBuffer, 79 | 0, 80 | messageBuffer.length, 81 | serverPort, 82 | serverAddress, 83 | (error) => { 84 | if (error) { 85 | console.error("Error sending message:", error); 86 | } else { 87 | // console.log( 88 | // `Message sent to ${serverAddress}:${serverPort}: ${hexString}` 89 | // ); 90 | } 91 | } 92 | ); 93 | 94 | // Listen for messages from the server 95 | client.on("message", async (msg, rinfo) => { 96 | client.close(); // Close the client socket after receiving the message 97 | const response = msg.toString("hex"); 98 | ms = response; 99 | const headerlength = 24; 100 | const header = response.substring(0, headerlength); 101 | const questionCount = parseInt(header.substring(8, 12), 16); 102 | const answerCount = parseInt(header.substring(12, 16), 16); 103 | const authorityCount = parseInt(header.substring(16, 20), 16); 104 | const additionalCount = parseInt(header.substring(20, 24), 16); 105 | let body = response.substring(headerlength); 106 | let name = ""; 107 | while (1) { 108 | const firstOctet = body.substring(0, 2); 109 | const decimal = parseInt(firstOctet, 16); 110 | if (firstOctet === "00") { 111 | break; 112 | } 113 | for (let i = 0; i < decimal; i++) { 114 | const temp = body.substring(2 + i * 2, 4 + i * 2); 115 | const ascii = parseInt(temp, 16); 116 | name += String.fromCharCode(ascii); 117 | } 118 | body = body.substring(2 + decimal * 2); 119 | } 120 | let rest = body.substring(2); 121 | const queryType = rest.substring(0, 4); 122 | const queryClass = rest.substring(4, 8); 123 | rest = rest.substring(8); 124 | // console.log("Query name:", name); 125 | // console.log("Query type:", queryType); 126 | // console.log("Query class:", queryClass); 127 | // console.log("Answer count:", answerCount); 128 | // console.log("Authority count:", authorityCount); 129 | // console.log("Additional count:", additionalCount); 130 | console.log( 131 | "Authority:", 132 | authorityCount, 133 | "Additional:", 134 | additionalCount, 135 | "Answer:", 136 | answerCount 137 | ); 138 | 139 | if (answerCount > 0) { 140 | // console.log("Answer"); 141 | for (let i = 0; i < answerCount; i++) { 142 | const firstOctet = rest.substring(0, 2); 143 | const decimal = parseInt(firstOctet, 16); 144 | const isPointer = decimal & 192; //checking if first 2 bits are set 145 | let nameData = ""; 146 | let nameLength = 0; //becaue name can be pointer or sequence of labels 147 | let name = ""; 148 | if (isPointer) { 149 | nameLength = 4; 150 | nameData = rest.substring(0, nameLength); 151 | name = decodeDomain(nameData); 152 | } else { 153 | // nameLength = decimal * 2 + 6; 154 | // nameData = rest.substring(0, nameLength); 155 | // name = decodeDomain(nameData); 156 | 157 | let temp = rest; 158 | while (1) { 159 | const octet = temp.substring(0, 2); 160 | if (octet == "00") { 161 | nameData += "00"; 162 | nameLength += 2; 163 | break; 164 | } 165 | let len = parseInt(octet, 16); 166 | temp = temp.substring(2); 167 | nameData += octet; 168 | nameLength += 2; 169 | nameData += temp.substring(0, 2 * len); 170 | temp = temp.substring(2 * len); 171 | nameLength += 2 * len; 172 | } 173 | name = decodeDomain(nameData); 174 | } 175 | const type = rest.substring(nameLength, nameLength + 4); 176 | const class_ = rest.substring(nameLength + 4, nameLength + 8); 177 | const ttl = rest.substring(nameLength + 8, nameLength + 16); 178 | const dataLength = rest.substring(nameLength + 16, nameLength + 20); 179 | const rdata = rest.substring( 180 | nameLength + 20, 181 | nameLength + 20 + parseInt(dataLength, 16) * 2 182 | ); 183 | rest = rest.substring(nameLength + 20 + parseInt(dataLength, 16) * 2); 184 | // console.log("Type:", type); 185 | if (type === "0001") { 186 | // console.log("Name:", name); 187 | // console.log("Type:", type); 188 | // console.log("Class:", class_); 189 | // console.log("Ttl:", ttl); 190 | // console.log("DataLength:", dataLength); 191 | // console.log(); 192 | resolve(decodeARecord(rdata)); 193 | console.log(); 194 | console.log("FOUND!"); 195 | console.log("Decoded name:", name); 196 | // console.log("decoded A Record", decodeARecord(rdata)); 197 | return; 198 | } 199 | if (type === "0005") { 200 | const CNAME = decodeDomain(rdata).slice(0, -1); 201 | console.log("CNAME:", CNAME); 202 | console.log(); 203 | const ip = await resolveDNS(CNAME, "198.41.0.4"); 204 | resolve(ip); 205 | return; 206 | } 207 | } 208 | } 209 | 210 | // console.log("Authority"); 211 | for (let i = 0; i < authorityCount; i++) { 212 | const firstOctet = rest.substring(0, 2); 213 | const decimal = parseInt(firstOctet, 16); 214 | const isPointer = decimal & 192; //checking if first 2 bits are set 215 | let nameData = ""; 216 | let nameLength = 0; //becaue name can be pointer or sequence of labels 217 | let name = ""; 218 | if (isPointer) { 219 | nameLength = 4; 220 | nameData = rest.substring(0, nameLength); 221 | name = decodeDomain(nameData); 222 | } else { 223 | // nameLength = decimal * 2 + 6; 224 | // nameData = rest.substring(0, nameLength); 225 | // name = decodeDomain(nameData); 226 | // console.log("nameData", nameData) 227 | // console.log("decimal", decimal) 228 | // console.log("firstOctet", firstOctet) 229 | 230 | let temp = rest; 231 | while (1) { 232 | const octet = temp.substring(0, 2); 233 | if (octet == "00") { 234 | nameData += "00"; 235 | nameLength += 2; 236 | break; 237 | } 238 | let len = parseInt(octet, 16); 239 | temp = temp.substring(2); 240 | nameData += octet; 241 | nameLength += 2; 242 | nameData += temp.substring(0, 2 * len); 243 | temp = temp.substring(2 * len); 244 | nameLength += 2 * len; 245 | } 246 | name = decodeDomain(nameData); 247 | } 248 | const type = rest.substring(nameLength, nameLength + 4); 249 | const class_ = rest.substring(nameLength + 4, nameLength + 8); 250 | const ttl = rest.substring(nameLength + 8, nameLength + 16); 251 | const dataLength = rest.substring(nameLength + 16, nameLength + 20); 252 | const rdata = rest.substring( 253 | nameLength + 20, 254 | nameLength + 20 + parseInt(dataLength, 16) * 2 255 | ); 256 | rest = rest.substring(nameLength + 20 + parseInt(dataLength, 16) * 2); 257 | // console.log("Name:", name); 258 | // console.log("Type:", type); 259 | // console.log("Class:", class_); 260 | // console.log("Ttl:", ttl); 261 | // console.log("DataLength:", dataLength); 262 | let decodedDomain = decodeDomain(rdata).slice(0, -1); 263 | 264 | console.log("Using Authoritaive nameserver:", decodedDomain); 265 | console.log(); 266 | if (type === "0002") { 267 | //NS record 268 | // const ip = await resolveDNS(decodedDomain, rootServer); 269 | const ip = await x(decodedDomain, rootServer); 270 | resolve(resolveDNS(hostname, ip)); 271 | // resolve(resolveDNS(hostname, decodedDomain)); 272 | break; 273 | } 274 | // console.log(); 275 | } 276 | 277 | // console.log("Additional"); 278 | for (let i = 0; i < additionalCount; i++) { 279 | const firstOctet = rest.substring(0, 2); 280 | const decimal = parseInt(firstOctet, 16); 281 | const isPointer = decimal & 192; //checking if first 2 bits are set 282 | let nameData = ""; 283 | let nameLength = 0; //becaue name can be pointer or sequence of labels 284 | let name = ""; 285 | if (isPointer) { 286 | nameLength = 4; 287 | nameData = rest.substring(0, nameLength); 288 | name = decodeDomain(nameData); 289 | } else { 290 | // nameLength = decimal * 2 + 6; 291 | // nameData = rest.substring(0, nameLength); 292 | // name = decodeDomain(nameData); 293 | 294 | let temp = rest; 295 | while (1) { 296 | const octet = temp.substring(0, 2); 297 | if (octet == "00") { 298 | nameData += "00"; 299 | nameLength += 2; 300 | break; 301 | } 302 | let len = parseInt(octet, 16); 303 | temp = temp.substring(2); 304 | nameData += octet; 305 | nameLength += 2; 306 | nameData += temp.substring(0, 2 * len); 307 | temp = temp.substring(2 * len); 308 | nameLength += 2 * len; 309 | } 310 | name = decodeDomain(nameData); 311 | } 312 | const type = rest.substring(nameLength, nameLength + 4); 313 | const class_ = rest.substring(nameLength + 4, nameLength + 8); 314 | const ttl = rest.substring(nameLength + 8, nameLength + 16); 315 | const dataLength = rest.substring(nameLength + 16, nameLength + 20); 316 | const rdata = rest.substring( 317 | nameLength + 20, 318 | nameLength + 20 + parseInt(dataLength, 16) * 2 319 | ); 320 | rest = rest.substring(nameLength + 20 + parseInt(dataLength, 16) * 2); 321 | if (type === "0001") { 322 | // console.log("Name:", name); 323 | // console.log("Type:", type); 324 | // console.log("Class:", class_); 325 | // console.log("Ttl:", ttl); 326 | // console.log("DataLength:", dataLength); 327 | // console.log("Decoded nameserver:", decodeDomain(rdata)); 328 | // console.log(); 329 | // if (type === "0001") { 330 | // resolveDNS(hostname, decodeARecord(rdata)); 331 | // break; 332 | // } 333 | } 334 | } 335 | }); 336 | }); 337 | } 338 | 339 | // const rootServer = "199.7.83.42" 340 | // const rootServer = "199.43.135.53"; 341 | // const rootServer = "142.250.192.5" 342 | // const hostname = "www.example.com"; 343 | // const hostname = "ride.swiggy.com"; 344 | // const hostname = "ns-ride-swiggy-com-1968196709.ap-southeast-1.elb.amazonaws.com" 345 | // const hostname = "dns.cloudflare.com"; 346 | // const hostname = "a.gtld-servers.net"; 347 | // const hostname = "amazon.in"; 348 | // const hostname = "www.amazon.in"; 349 | // const hostname = "fresh.amazon.com"; 350 | // const hostname = "amazon.in"; 351 | // const hostname = "tp.c95e7e602-frontier.amazon.in" 352 | // const hostname = "www.woohoo.in"; 353 | // const hostname = "woohoo.in"; 354 | 355 | async function main() { 356 | const args = process.argv; 357 | let hostname = args[2]; 358 | if (!hostname) { 359 | hostname = "www.example.com"; 360 | } 361 | const result = await resolveDNS(hostname, rootServer); 362 | console.log("IP Address:", result); 363 | } 364 | main(); 365 | -------------------------------------------------------------------------------- /dns-resolver-utility.js: -------------------------------------------------------------------------------- 1 | import dgram from "dgram"; 2 | 3 | const rootServer = "198.41.0.4"; 4 | function encodeURL(str) { 5 | const temp = 6 | str 7 | .split(".") 8 | .map( 9 | (s) => 10 | s.length.toString(16).padStart(2, 0) + 11 | s 12 | .split("") 13 | .map((c) => c.charCodeAt(0).toString(16).padStart(2, 0)) 14 | .join("") 15 | ) 16 | .join("") + "00"; 17 | 18 | return temp; 19 | } 20 | 21 | let ms = ""; 22 | 23 | function decodeDomain(str) { 24 | // console.log("---") 25 | let ans = ""; 26 | const octet = str.substring(0, 2); 27 | const decimal = parseInt(octet, 16); 28 | const isPointer = decimal & 192; //checking if first 2 bits are set 29 | if (octet === "00") { 30 | return ""; 31 | } 32 | if (isPointer) { 33 | const doubleOctet = str.substring(0, 4); 34 | const mask = 16383; 35 | const doubleDecimal = parseInt(doubleOctet, 16); 36 | const offset = doubleDecimal & mask; 37 | ans += decodeDomain(ms.substring(offset * 2)); 38 | } else { 39 | //it is sequence of labels 40 | let ptr = 2; 41 | let local = ""; 42 | for (let i = 0; i < decimal; i++) { 43 | const temp = str.substring(ptr, ptr + 2); 44 | const ascii = parseInt(temp, 16); 45 | local += String.fromCharCode(ascii); 46 | ptr += 2; 47 | } 48 | ans += local + "." + decodeDomain(str.substring(ptr)); 49 | } 50 | return ans; 51 | } 52 | 53 | function decodeARecord(str) { 54 | let ans = ""; 55 | for (let i = 0; i < str.length; i += 2) { 56 | const temp = str.substring(i, i + 2); 57 | const ascii = parseInt(temp, 16); 58 | ans += ascii; 59 | if (i < str.length - 2) { 60 | ans += "."; 61 | } 62 | } 63 | return ans; 64 | } 65 | 66 | export async function resolveDNS(hostname, serverAddress) { 67 | return new Promise((resolve, reject) => { 68 | const client = dgram.createSocket("udp4"); 69 | // console.log("Resolving DNS for ", hostname, "at ", serverAddress); 70 | const hexString = 71 | "001600000001000000000000" + encodeURL(hostname) + "00010001"; 72 | 73 | const messageBuffer = Buffer.from(hexString, "hex"); 74 | const serverPort = 53; // Replace with the port of your UDP server 75 | 76 | client.send( 77 | messageBuffer, 78 | 0, 79 | messageBuffer.length, 80 | serverPort, 81 | serverAddress, 82 | (error) => { 83 | if (error) { 84 | console.error("Error sending message:", error); 85 | } else { 86 | // console.log( 87 | // `Message sent to ${serverAddress}:${serverPort}: ${hexString}` 88 | // ); 89 | } 90 | } 91 | ); 92 | 93 | // Listen for messages from the server 94 | client.on("message", async (msg, rinfo) => { 95 | // console.log("Received"); 96 | // console.log(msg.toString("hex")); 97 | client.close(); // Close the client socket after receiving the message 98 | const response = msg.toString("hex"); 99 | ms = response; 100 | const headerlength = 24; 101 | const header = response.substring(0, headerlength); 102 | const questionCount = parseInt(header.substring(8, 12), 16); 103 | const answerCount = parseInt(header.substring(12, 16), 16); 104 | const authorityCount = parseInt(header.substring(16, 20), 16); 105 | const additionalCount = parseInt(header.substring(20, 24), 16); 106 | let body = response.substring(headerlength); 107 | let name = ""; 108 | while (1) { 109 | const firstOctet = body.substring(0, 2); 110 | const decimal = parseInt(firstOctet, 16); 111 | if (firstOctet === "00") { 112 | break; 113 | } 114 | for (let i = 0; i < decimal; i++) { 115 | const temp = body.substring(2 + i * 2, 4 + i * 2); 116 | const ascii = parseInt(temp, 16); 117 | name += String.fromCharCode(ascii); 118 | } 119 | body = body.substring(2 + decimal * 2); 120 | } 121 | let rest = body.substring(2); 122 | const queryType = rest.substring(0, 4); 123 | const queryClass = rest.substring(4, 8); 124 | rest = rest.substring(8); 125 | // console.log("Query name:", name); 126 | // console.log("Query type:", queryType); 127 | // console.log("Query class:", queryClass); 128 | // console.log("Answer count:", answerCount); 129 | // console.log("Authority count:", authorityCount); 130 | // console.log("Additional count:", additionalCount); 131 | 132 | if (answerCount > 0) { 133 | // console.log("Answer"); 134 | for (let i = 0; i < answerCount; i++) { 135 | const firstOctet = rest.substring(0, 2); 136 | const decimal = parseInt(firstOctet, 16); 137 | const isPointer = decimal & 192; //checking if first 2 bits are set 138 | let nameData = ""; 139 | let nameLength = 0; //becaue name can be pointer or sequence of labels 140 | let name = ""; 141 | if (isPointer) { 142 | nameLength = 4; 143 | nameData = rest.substring(0, nameLength); 144 | name = decodeDomain(nameData); 145 | } else { 146 | // nameLength = decimal * 2 + 6; 147 | // nameData = rest.substring(0, nameLength); 148 | // name = decodeDomain(nameData); 149 | 150 | let temp = rest; 151 | while (1) { 152 | const octet = temp.substring(0, 2); 153 | if (octet == "00") { 154 | nameData += "00"; 155 | nameLength += 2; 156 | break; 157 | } 158 | let len = parseInt(octet, 16); 159 | temp = temp.substring(2); 160 | nameData += octet; 161 | nameLength += 2; 162 | nameData += temp.substring(0, 2 * len); 163 | temp = temp.substring(2 * len); 164 | nameLength += 2 * len; 165 | } 166 | name = decodeDomain(nameData); 167 | } 168 | const type = rest.substring(nameLength, nameLength + 4); 169 | const class_ = rest.substring(nameLength + 4, nameLength + 8); 170 | const ttl = rest.substring(nameLength + 8, nameLength + 16); 171 | const dataLength = rest.substring(nameLength + 16, nameLength + 20); 172 | const rdata = rest.substring( 173 | nameLength + 20, 174 | nameLength + 20 + parseInt(dataLength, 16) * 2 175 | ); 176 | rest = rest.substring(nameLength + 20 + parseInt(dataLength, 16) * 2); 177 | // console.log("Type:", type); 178 | if (type === "0001") { 179 | // console.log("Name:", name); 180 | // console.log("Type:", type); 181 | // console.log("Class:", class_); 182 | // console.log("Ttl:", ttl); 183 | // console.log("DataLength:", dataLength); 184 | // console.log(); 185 | resolve(decodeARecord(rdata)); 186 | // console.log(); 187 | // console.log("FOUND!"); 188 | // console.log("decoded name", name); 189 | // console.log("decoded A Record", decodeARecord(rdata)); 190 | return; 191 | } 192 | } 193 | } 194 | 195 | // console.log("Authority"); 196 | for (let i = 0; i < authorityCount; i++) { 197 | const firstOctet = rest.substring(0, 2); 198 | const decimal = parseInt(firstOctet, 16); 199 | const isPointer = decimal & 192; //checking if first 2 bits are set 200 | let nameData = ""; 201 | let nameLength = 0; //becaue name can be pointer or sequence of labels 202 | let name = ""; 203 | if (isPointer) { 204 | nameLength = 4; 205 | nameData = rest.substring(0, nameLength); 206 | name = decodeDomain(nameData); 207 | } else { 208 | // nameLength = decimal * 2 + 6; 209 | // nameData = rest.substring(0, nameLength); 210 | // name = decodeDomain(nameData); 211 | // console.log("nameData", nameData) 212 | // console.log("decimal", decimal) 213 | // console.log("firstOctet", firstOctet) 214 | 215 | let temp = rest; 216 | while (1) { 217 | const octet = temp.substring(0, 2); 218 | if (octet == "00") { 219 | nameData += "00"; 220 | nameLength += 2; 221 | break; 222 | } 223 | let len = parseInt(octet, 16); 224 | temp = temp.substring(2); 225 | nameData += octet; 226 | nameLength += 2; 227 | nameData += temp.substring(0, 2 * len); 228 | temp = temp.substring(2 * len); 229 | nameLength += 2 * len; 230 | } 231 | name = decodeDomain(nameData); 232 | } 233 | const type = rest.substring(nameLength, nameLength + 4); 234 | const class_ = rest.substring(nameLength + 4, nameLength + 8); 235 | const ttl = rest.substring(nameLength + 8, nameLength + 16); 236 | const dataLength = rest.substring(nameLength + 16, nameLength + 20); 237 | const rdata = rest.substring( 238 | nameLength + 20, 239 | nameLength + 20 + parseInt(dataLength, 16) * 2 240 | ); 241 | rest = rest.substring(nameLength + 20 + parseInt(dataLength, 16) * 2); 242 | // console.log("Name:", name); 243 | // console.log("Type:", type); 244 | // console.log("Class:", class_); 245 | // console.log("Ttl:", ttl); 246 | // console.log("DataLength:", dataLength); 247 | let decodedDomain = decodeDomain(rdata).slice(0, -1); 248 | 249 | // console.log("Found Authoritaive nameserver:", decodedDomain); 250 | // console.log(); 251 | if (type === "0002") { 252 | //NS 253 | // const ip = await x(decodedDomain, rootServer); 254 | // resolve(resolveDNS(hostname, ip)); 255 | resolve(resolveDNS(hostname, decodedDomain)); 256 | break; 257 | } 258 | // console.log(); 259 | } 260 | 261 | // console.log("Additional"); 262 | for (let i = 0; i < additionalCount; i++) { 263 | const firstOctet = rest.substring(0, 2); 264 | const decimal = parseInt(firstOctet, 16); 265 | const isPointer = decimal & 192; //checking if first 2 bits are set 266 | let nameData = ""; 267 | let nameLength = 0; //becaue name can be pointer or sequence of labels 268 | let name = ""; 269 | if (isPointer) { 270 | nameLength = 4; 271 | nameData = rest.substring(0, nameLength); 272 | name = decodeDomain(nameData); 273 | } else { 274 | // nameLength = decimal * 2 + 6; 275 | // nameData = rest.substring(0, nameLength); 276 | // name = decodeDomain(nameData); 277 | 278 | let temp = rest; 279 | while (1) { 280 | const octet = temp.substring(0, 2); 281 | if (octet == "00") { 282 | nameData += "00"; 283 | nameLength += 2; 284 | break; 285 | } 286 | let len = parseInt(octet, 16); 287 | temp = temp.substring(2); 288 | nameData += octet; 289 | nameLength += 2; 290 | nameData += temp.substring(0, 2 * len); 291 | temp = temp.substring(2 * len); 292 | nameLength += 2 * len; 293 | } 294 | name = decodeDomain(nameData); 295 | } 296 | const type = rest.substring(nameLength, nameLength + 4); 297 | const class_ = rest.substring(nameLength + 4, nameLength + 8); 298 | const ttl = rest.substring(nameLength + 8, nameLength + 16); 299 | const dataLength = rest.substring(nameLength + 16, nameLength + 20); 300 | const rdata = rest.substring( 301 | nameLength + 20, 302 | nameLength + 20 + parseInt(dataLength, 16) * 2 303 | ); 304 | rest = rest.substring(nameLength + 20 + parseInt(dataLength, 16) * 2); 305 | if (type === "0001") { 306 | // console.log("Name:", name); 307 | // console.log("Type:", type); 308 | // console.log("Class:", class_); 309 | // console.log("Ttl:", ttl); 310 | // console.log("DataLength:", dataLength); 311 | // console.log("Decoded nameserver:", decodeDomain(rdata)); 312 | // console.log(); 313 | } 314 | } 315 | }); 316 | }); 317 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dns-resolver-nodejs", 3 | "version": "1.0.0", 4 | "description": "DNS Resolved written in NodeJS from scratch.", 5 | "type": "module", 6 | "main": "dns-resolver-async.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "DNS" 12 | ], 13 | "author": "Vishal Gaurav", 14 | "license": "ISC" 15 | } 16 | --------------------------------------------------------------------------------