1// Flags: --expose-internals 2// Copyright Joyent, Inc. and other Node contributors. 3// 4// Permission is hereby granted, free of charge, to any person obtaining a 5// copy of this software and associated documentation files (the 6// "Software"), to deal in the Software without restriction, including 7// without limitation the rights to use, copy, modify, merge, publish, 8// distribute, sublicense, and/or sell copies of the Software, and to permit 9// persons to whom the Software is furnished to do so, subject to the 10// following conditions: 11// 12// The above copyright notice and this permission notice shall be included 13// in all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 18// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21// USE OR OTHER DEALINGS IN THE SOFTWARE. 22 23'use strict'; 24const common = require('../common'); 25const { addresses } = require('../common/internet'); 26const { internalBinding } = require('internal/test/binding'); 27const { getSystemErrorName } = require('util'); 28const assert = require('assert'); 29const dns = require('dns'); 30const net = require('net'); 31const isIPv4 = net.isIPv4; 32const isIPv6 = net.isIPv6; 33const util = require('util'); 34const dnsPromises = dns.promises; 35 36let expected = 0; 37let completed = 0; 38let running = false; 39const queue = []; 40 41 42function TEST(f) { 43 function next() { 44 const f = queue.shift(); 45 if (f) { 46 running = true; 47 console.log(f.name); 48 f(done); 49 } 50 } 51 52 function done() { 53 running = false; 54 completed++; 55 process.nextTick(next); 56 } 57 58 expected++; 59 queue.push(f); 60 61 if (!running) { 62 next(); 63 } 64} 65 66 67function checkWrap(req) { 68 assert.strictEqual(typeof req, 'object'); 69} 70 71 72TEST(function test_reverse_bogus(done) { 73 dnsPromises.reverse('bogus ip') 74 .then(common.mustNotCall()) 75 .catch(common.mustCall((err) => { 76 assert.strictEqual(err.code, 'EINVAL'); 77 assert.strictEqual(getSystemErrorName(err.errno), 'EINVAL'); 78 })); 79 80 assert.throws(() => { 81 dns.reverse('bogus ip', common.mustNotCall()); 82 }, /^Error: getHostByAddr EINVAL bogus ip$/); 83 done(); 84}); 85 86TEST(async function test_resolve4_ttl(done) { 87 function validateResult(result) { 88 assert.ok(result.length > 0); 89 90 for (const item of result) { 91 assert.strictEqual(typeof item, 'object'); 92 assert.strictEqual(typeof item.ttl, 'number'); 93 assert.strictEqual(typeof item.address, 'string'); 94 assert.ok(item.ttl >= 0); 95 assert.ok(isIPv4(item.address)); 96 } 97 } 98 99 validateResult(await dnsPromises.resolve4(addresses.INET4_HOST, { 100 ttl: true 101 })); 102 103 const req = dns.resolve4(addresses.INET4_HOST, { 104 ttl: true 105 }, function(err, result) { 106 assert.ifError(err); 107 validateResult(result); 108 done(); 109 }); 110 111 checkWrap(req); 112}); 113 114TEST(async function test_resolve6_ttl(done) { 115 function validateResult(result) { 116 assert.ok(result.length > 0); 117 118 for (const item of result) { 119 assert.strictEqual(typeof item, 'object'); 120 assert.strictEqual(typeof item.ttl, 'number'); 121 assert.strictEqual(typeof item.address, 'string'); 122 assert.ok(item.ttl >= 0); 123 assert.ok(isIPv6(item.address)); 124 } 125 } 126 127 validateResult(await dnsPromises.resolve6(addresses.INET6_HOST, { 128 ttl: true 129 })); 130 131 const req = dns.resolve6(addresses.INET6_HOST, { 132 ttl: true 133 }, function(err, result) { 134 assert.ifError(err); 135 validateResult(result); 136 done(); 137 }); 138 139 checkWrap(req); 140}); 141 142TEST(async function test_resolveMx(done) { 143 function validateResult(result) { 144 assert.ok(result.length > 0); 145 146 for (const item of result) { 147 assert.strictEqual(typeof item, 'object'); 148 assert.ok(item.exchange); 149 assert.strictEqual(typeof item.exchange, 'string'); 150 assert.strictEqual(typeof item.priority, 'number'); 151 } 152 } 153 154 validateResult(await dnsPromises.resolveMx(addresses.MX_HOST)); 155 156 const req = dns.resolveMx(addresses.MX_HOST, function(err, result) { 157 assert.ifError(err); 158 validateResult(result); 159 done(); 160 }); 161 162 checkWrap(req); 163}); 164 165TEST(function test_resolveMx_failure(done) { 166 dnsPromises.resolveMx(addresses.NOT_FOUND) 167 .then(common.mustNotCall()) 168 .catch(common.mustCall((err) => { 169 assert.strictEqual(err.code, 'ENOTFOUND'); 170 })); 171 172 const req = dns.resolveMx(addresses.NOT_FOUND, function(err, result) { 173 assert.ok(err instanceof Error); 174 assert.strictEqual(err.code, 'ENOTFOUND'); 175 176 assert.strictEqual(result, undefined); 177 178 done(); 179 }); 180 181 checkWrap(req); 182}); 183 184TEST(async function test_resolveNs(done) { 185 function validateResult(result) { 186 assert.ok(result.length > 0); 187 188 for (const item of result) { 189 assert.ok(item); 190 assert.strictEqual(typeof item, 'string'); 191 } 192 } 193 194 validateResult(await dnsPromises.resolveNs(addresses.NS_HOST)); 195 196 const req = dns.resolveNs(addresses.NS_HOST, function(err, names) { 197 assert.ifError(err); 198 validateResult(names); 199 done(); 200 }); 201 202 checkWrap(req); 203}); 204 205TEST(function test_resolveNs_failure(done) { 206 dnsPromises.resolveNs(addresses.NOT_FOUND) 207 .then(common.mustNotCall()) 208 .catch(common.mustCall((err) => { 209 assert.strictEqual(err.code, 'ENOTFOUND'); 210 })); 211 212 const req = dns.resolveNs(addresses.NOT_FOUND, function(err, result) { 213 assert.ok(err instanceof Error); 214 assert.strictEqual(err.code, 'ENOTFOUND'); 215 216 assert.strictEqual(result, undefined); 217 218 done(); 219 }); 220 221 checkWrap(req); 222}); 223 224TEST(async function test_resolveSrv(done) { 225 function validateResult(result) { 226 assert.ok(result.length > 0); 227 228 for (const item of result) { 229 assert.strictEqual(typeof item, 'object'); 230 assert.ok(item.name); 231 assert.strictEqual(typeof item.name, 'string'); 232 assert.strictEqual(typeof item.port, 'number'); 233 assert.strictEqual(typeof item.priority, 'number'); 234 assert.strictEqual(typeof item.weight, 'number'); 235 } 236 } 237 238 validateResult(await dnsPromises.resolveSrv(addresses.SRV_HOST)); 239 240 const req = dns.resolveSrv(addresses.SRV_HOST, function(err, result) { 241 assert.ifError(err); 242 validateResult(result); 243 done(); 244 }); 245 246 checkWrap(req); 247}); 248 249TEST(function test_resolveSrv_failure(done) { 250 dnsPromises.resolveSrv(addresses.NOT_FOUND) 251 .then(common.mustNotCall()) 252 .catch(common.mustCall((err) => { 253 assert.strictEqual(err.code, 'ENOTFOUND'); 254 })); 255 256 const req = dns.resolveSrv(addresses.NOT_FOUND, function(err, result) { 257 assert.ok(err instanceof Error); 258 assert.strictEqual(err.code, 'ENOTFOUND'); 259 260 assert.strictEqual(result, undefined); 261 262 done(); 263 }); 264 265 checkWrap(req); 266}); 267 268TEST(async function test_resolvePtr(done) { 269 function validateResult(result) { 270 assert.ok(result.length > 0); 271 272 for (const item of result) { 273 assert.ok(item); 274 assert.strictEqual(typeof item, 'string'); 275 } 276 } 277 278 validateResult(await dnsPromises.resolvePtr(addresses.PTR_HOST)); 279 280 const req = dns.resolvePtr(addresses.PTR_HOST, function(err, result) { 281 assert.ifError(err); 282 validateResult(result); 283 done(); 284 }); 285 286 checkWrap(req); 287}); 288 289TEST(function test_resolvePtr_failure(done) { 290 dnsPromises.resolvePtr(addresses.NOT_FOUND) 291 .then(common.mustNotCall()) 292 .catch(common.mustCall((err) => { 293 assert.strictEqual(err.code, 'ENOTFOUND'); 294 })); 295 296 const req = dns.resolvePtr(addresses.NOT_FOUND, function(err, result) { 297 assert.ok(err instanceof Error); 298 assert.strictEqual(err.code, 'ENOTFOUND'); 299 300 assert.strictEqual(result, undefined); 301 302 done(); 303 }); 304 305 checkWrap(req); 306}); 307 308TEST(async function test_resolveNaptr(done) { 309 function validateResult(result) { 310 assert.ok(result.length > 0); 311 312 for (const item of result) { 313 assert.strictEqual(typeof item, 'object'); 314 assert.strictEqual(typeof item.flags, 'string'); 315 assert.strictEqual(typeof item.service, 'string'); 316 assert.strictEqual(typeof item.regexp, 'string'); 317 assert.strictEqual(typeof item.replacement, 'string'); 318 assert.strictEqual(typeof item.order, 'number'); 319 assert.strictEqual(typeof item.preference, 'number'); 320 } 321 } 322 323 validateResult(await dnsPromises.resolveNaptr(addresses.NAPTR_HOST)); 324 325 const req = dns.resolveNaptr(addresses.NAPTR_HOST, function(err, result) { 326 assert.ifError(err); 327 validateResult(result); 328 done(); 329 }); 330 331 checkWrap(req); 332}); 333 334TEST(function test_resolveNaptr_failure(done) { 335 dnsPromises.resolveNaptr(addresses.NOT_FOUND) 336 .then(common.mustNotCall()) 337 .catch(common.mustCall((err) => { 338 assert.strictEqual(err.code, 'ENOTFOUND'); 339 })); 340 341 const req = dns.resolveNaptr(addresses.NOT_FOUND, function(err, result) { 342 assert.ok(err instanceof Error); 343 assert.strictEqual(err.code, 'ENOTFOUND'); 344 345 assert.strictEqual(result, undefined); 346 347 done(); 348 }); 349 350 checkWrap(req); 351}); 352 353TEST(async function test_resolveSoa(done) { 354 function validateResult(result) { 355 assert.strictEqual(typeof result, 'object'); 356 assert.strictEqual(typeof result.nsname, 'string'); 357 assert.ok(result.nsname.length > 0); 358 assert.strictEqual(typeof result.hostmaster, 'string'); 359 assert.ok(result.hostmaster.length > 0); 360 assert.strictEqual(typeof result.serial, 'number'); 361 assert.ok((result.serial > 0) && (result.serial < 4294967295)); 362 assert.strictEqual(typeof result.refresh, 'number'); 363 assert.ok((result.refresh > 0) && (result.refresh < 2147483647)); 364 assert.strictEqual(typeof result.retry, 'number'); 365 assert.ok((result.retry > 0) && (result.retry < 2147483647)); 366 assert.strictEqual(typeof result.expire, 'number'); 367 assert.ok((result.expire > 0) && (result.expire < 2147483647)); 368 assert.strictEqual(typeof result.minttl, 'number'); 369 assert.ok((result.minttl >= 0) && (result.minttl < 2147483647)); 370 } 371 372 validateResult(await dnsPromises.resolveSoa(addresses.SOA_HOST)); 373 374 const req = dns.resolveSoa(addresses.SOA_HOST, function(err, result) { 375 assert.ifError(err); 376 validateResult(result); 377 done(); 378 }); 379 380 checkWrap(req); 381}); 382 383TEST(function test_resolveSoa_failure(done) { 384 dnsPromises.resolveSoa(addresses.NOT_FOUND) 385 .then(common.mustNotCall()) 386 .catch(common.mustCall((err) => { 387 assert.strictEqual(err.code, 'ENOTFOUND'); 388 })); 389 390 const req = dns.resolveSoa(addresses.NOT_FOUND, function(err, result) { 391 assert.ok(err instanceof Error); 392 assert.strictEqual(err.code, 'ENOTFOUND'); 393 394 assert.strictEqual(result, undefined); 395 396 done(); 397 }); 398 399 checkWrap(req); 400}); 401 402TEST(async function test_resolveCaa(done) { 403 function validateResult(result) { 404 assert.ok(Array.isArray(result), 405 `expected array, got ${util.inspect(result)}`); 406 assert.strictEqual(result.length, 1); 407 assert.strictEqual(typeof result[0].critical, 'number'); 408 assert.strictEqual(result[0].critical, 0); 409 assert.strictEqual(result[0].issue, 'pki.goog'); 410 } 411 412 validateResult(await dnsPromises.resolveCaa(addresses.CAA_HOST)); 413 414 const req = dns.resolveCaa(addresses.CAA_HOST, function(err, records) { 415 assert.ifError(err); 416 validateResult(records); 417 done(); 418 }); 419 420 checkWrap(req); 421}); 422 423TEST(function test_resolveCaa_failure(done) { 424 dnsPromises.resolveTxt(addresses.NOT_FOUND) 425 .then(common.mustNotCall()) 426 .catch(common.mustCall((err) => { 427 assert.strictEqual(err.code, 'ENOTFOUND'); 428 })); 429 430 const req = dns.resolveCaa(addresses.NOT_FOUND, function(err, result) { 431 assert.ok(err instanceof Error); 432 assert.strictEqual(err.code, 'ENOTFOUND'); 433 434 assert.strictEqual(result, undefined); 435 436 done(); 437 }); 438 439 checkWrap(req); 440}); 441 442TEST(async function test_resolveCname(done) { 443 function validateResult(result) { 444 assert.ok(result.length > 0); 445 446 for (const item of result) { 447 assert.ok(item); 448 assert.strictEqual(typeof item, 'string'); 449 } 450 } 451 452 validateResult(await dnsPromises.resolveCname(addresses.CNAME_HOST)); 453 454 const req = dns.resolveCname(addresses.CNAME_HOST, function(err, names) { 455 assert.ifError(err); 456 validateResult(names); 457 done(); 458 }); 459 460 checkWrap(req); 461}); 462 463TEST(function test_resolveCname_failure(done) { 464 dnsPromises.resolveCname(addresses.NOT_FOUND) 465 .then(common.mustNotCall()) 466 .catch(common.mustCall((err) => { 467 assert.strictEqual(err.code, 'ENOTFOUND'); 468 })); 469 470 const req = dns.resolveCname(addresses.NOT_FOUND, function(err, result) { 471 assert.ok(err instanceof Error); 472 assert.strictEqual(err.code, 'ENOTFOUND'); 473 474 assert.strictEqual(result, undefined); 475 476 done(); 477 }); 478 479 checkWrap(req); 480}); 481 482 483TEST(async function test_resolveTxt(done) { 484 function validateResult(result) { 485 assert.ok(Array.isArray(result[0])); 486 assert.strictEqual(result.length, 1); 487 assert(result[0][0].startsWith('v=spf1')); 488 } 489 490 validateResult(await dnsPromises.resolveTxt(addresses.TXT_HOST)); 491 492 const req = dns.resolveTxt(addresses.TXT_HOST, function(err, records) { 493 assert.ifError(err); 494 validateResult(records); 495 done(); 496 }); 497 498 checkWrap(req); 499}); 500 501TEST(function test_resolveTxt_failure(done) { 502 dnsPromises.resolveTxt(addresses.NOT_FOUND) 503 .then(common.mustNotCall()) 504 .catch(common.mustCall((err) => { 505 assert.strictEqual(err.code, 'ENOTFOUND'); 506 })); 507 508 const req = dns.resolveTxt(addresses.NOT_FOUND, function(err, result) { 509 assert.ok(err instanceof Error); 510 assert.strictEqual(err.code, 'ENOTFOUND'); 511 512 assert.strictEqual(result, undefined); 513 514 done(); 515 }); 516 517 checkWrap(req); 518}); 519 520 521TEST(function test_lookup_failure(done) { 522 dnsPromises.lookup(addresses.NOT_FOUND, 4) 523 .then(common.mustNotCall()) 524 .catch(common.expectsError({ code: dns.NOTFOUND })); 525 526 const req = dns.lookup(addresses.NOT_FOUND, 4, (err) => { 527 assert.ok(err instanceof Error); 528 assert.strictEqual(err.code, dns.NOTFOUND); 529 assert.strictEqual(err.code, 'ENOTFOUND'); 530 assert.ok(!/ENOENT/.test(err.message)); 531 assert.ok(err.message.includes(addresses.NOT_FOUND)); 532 533 done(); 534 }); 535 536 checkWrap(req); 537}); 538 539 540TEST(async function test_lookup_ip_all(done) { 541 function validateResult(result) { 542 assert.ok(Array.isArray(result)); 543 assert.ok(result.length > 0); 544 assert.strictEqual(result[0].address, '127.0.0.1'); 545 assert.strictEqual(result[0].family, 4); 546 } 547 548 validateResult(await dnsPromises.lookup('127.0.0.1', { all: true })); 549 550 const req = dns.lookup( 551 '127.0.0.1', 552 { all: true }, 553 function(err, ips, family) { 554 assert.ifError(err); 555 assert.strictEqual(family, undefined); 556 validateResult(ips); 557 done(); 558 } 559 ); 560 561 checkWrap(req); 562}); 563 564 565TEST(function test_lookup_ip_all_promise(done) { 566 const req = util.promisify(dns.lookup)('127.0.0.1', { all: true }) 567 .then(function(ips) { 568 assert.ok(Array.isArray(ips)); 569 assert.ok(ips.length > 0); 570 assert.strictEqual(ips[0].address, '127.0.0.1'); 571 assert.strictEqual(ips[0].family, 4); 572 573 done(); 574 }); 575 576 checkWrap(req); 577}); 578 579 580TEST(function test_lookup_ip_promise(done) { 581 util.promisify(dns.lookup)('127.0.0.1') 582 .then(function({ address, family }) { 583 assert.strictEqual(address, '127.0.0.1'); 584 assert.strictEqual(family, 4); 585 586 done(); 587 }); 588}); 589 590 591TEST(async function test_lookup_null_all(done) { 592 assert.deepStrictEqual(await dnsPromises.lookup(null, { all: true }), []); 593 594 const req = dns.lookup(null, { all: true }, (err, ips) => { 595 assert.ifError(err); 596 assert.ok(Array.isArray(ips)); 597 assert.strictEqual(ips.length, 0); 598 599 done(); 600 }); 601 602 checkWrap(req); 603}); 604 605 606TEST(async function test_lookup_all_mixed(done) { 607 function validateResult(result) { 608 assert.ok(Array.isArray(result)); 609 assert.ok(result.length > 0); 610 611 result.forEach(function(ip) { 612 if (isIPv4(ip.address)) 613 assert.strictEqual(ip.family, 4); 614 else if (isIPv6(ip.address)) 615 assert.strictEqual(ip.family, 6); 616 else 617 assert.fail('unexpected IP address'); 618 }); 619 } 620 621 validateResult(await dnsPromises.lookup(addresses.INET_HOST, { all: true })); 622 623 const req = dns.lookup(addresses.INET_HOST, { 624 all: true 625 }, function(err, ips) { 626 assert.ifError(err); 627 validateResult(ips); 628 done(); 629 }); 630 631 checkWrap(req); 632}); 633 634 635TEST(function test_lookupservice_invalid(done) { 636 dnsPromises.lookupService('1.2.3.4', 80) 637 .then(common.mustNotCall()) 638 .catch(common.expectsError({ code: 'ENOTFOUND' })); 639 640 const req = dns.lookupService('1.2.3.4', 80, (err) => { 641 assert(err instanceof Error); 642 assert.strictEqual(err.code, 'ENOTFOUND'); 643 assert.ok(/1\.2\.3\.4/.test(err.message)); 644 645 done(); 646 }); 647 648 checkWrap(req); 649}); 650 651 652TEST(function test_reverse_failure(done) { 653 dnsPromises.reverse('203.0.113.0') 654 .then(common.mustNotCall()) 655 .catch(common.expectsError({ 656 code: 'ENOTFOUND', 657 hostname: '203.0.113.0' 658 })); 659 660 // 203.0.113.0/24 are addresses reserved for (RFC) documentation use only 661 const req = dns.reverse('203.0.113.0', function(err) { 662 assert(err instanceof Error); 663 assert.strictEqual(err.code, 'ENOTFOUND'); // Silly error code... 664 assert.strictEqual(err.hostname, '203.0.113.0'); 665 assert.ok(/203\.0\.113\.0/.test(err.message)); 666 667 done(); 668 }); 669 670 checkWrap(req); 671}); 672 673 674TEST(function test_lookup_failure(done) { 675 dnsPromises.lookup(addresses.NOT_FOUND) 676 .then(common.mustNotCall()) 677 .catch(common.expectsError({ 678 code: 'ENOTFOUND', 679 hostname: addresses.NOT_FOUND 680 })); 681 682 const req = dns.lookup(addresses.NOT_FOUND, (err) => { 683 assert(err instanceof Error); 684 assert.strictEqual(err.code, 'ENOTFOUND'); // Silly error code... 685 assert.strictEqual(err.hostname, addresses.NOT_FOUND); 686 assert.ok(err.message.includes(addresses.NOT_FOUND)); 687 688 done(); 689 }); 690 691 checkWrap(req); 692}); 693 694 695TEST(function test_resolve_failure(done) { 696 const req = dns.resolve4(addresses.NOT_FOUND, (err) => { 697 assert(err instanceof Error); 698 699 switch (err.code) { 700 case 'ENOTFOUND': 701 case 'ESERVFAIL': 702 break; 703 default: 704 assert.strictEqual(err.code, 'ENOTFOUND'); // Silly error code... 705 break; 706 } 707 708 assert.strictEqual(err.hostname, addresses.NOT_FOUND); 709 assert.ok(err.message.includes(addresses.NOT_FOUND)); 710 711 done(); 712 }); 713 714 checkWrap(req); 715}); 716 717 718let getaddrinfoCallbackCalled = false; 719 720console.log(`looking up ${addresses.INET4_HOST}..`); 721 722const cares = internalBinding('cares_wrap'); 723const req = new cares.GetAddrInfoReqWrap(); 724cares.getaddrinfo(req, addresses.INET4_HOST, 4, 725 /* hints */ 0, /* verbatim */ true); 726 727req.oncomplete = function(err, domains) { 728 assert.strictEqual(err, 0); 729 console.log(`${addresses.INET4_HOST} = ${domains}`); 730 assert.ok(Array.isArray(domains)); 731 assert.ok(domains.length >= 1); 732 assert.strictEqual(typeof domains[0], 'string'); 733 getaddrinfoCallbackCalled = true; 734}; 735 736process.on('exit', function() { 737 console.log(`${completed} tests completed`); 738 assert.strictEqual(running, false); 739 assert.strictEqual(completed, expected); 740 assert.ok(getaddrinfoCallbackCalled); 741}); 742 743// Should not throw. 744dns.lookup(addresses.INET6_HOST, 6, common.mustCall()); 745dns.lookup(addresses.INET_HOST, {}, common.mustCall()); 746dns.lookupService('0.0.0.0', '0', common.mustCall()); 747dns.lookupService('0.0.0.0', 0, common.mustCall()); 748(async function() { 749 await dnsPromises.lookup(addresses.INET6_HOST, 6); 750 await dnsPromises.lookup(addresses.INET_HOST, {}); 751})().then(common.mustCall()); 752