11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst common = require('../common');
41cb0ef41Sopenharmony_ciconst { parseDNSPacket, writeDNSPacket } = require('../common/dns');
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ciconst assert = require('assert');
71cb0ef41Sopenharmony_ciconst dgram = require('dgram');
81cb0ef41Sopenharmony_ciconst { Resolver } = require('dns');
91cb0ef41Sopenharmony_ciconst { createConnection, createServer, setDefaultAutoSelectFamily } = require('net');
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ci// Test that the default for happy eyeballs algorithm is properly respected.
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_cilet autoSelectFamilyAttemptTimeout = common.platformTimeout(250);
141cb0ef41Sopenharmony_ciif (common.isWindows) {
151cb0ef41Sopenharmony_ci  // Some of the windows machines in the CI need more time to establish connection
161cb0ef41Sopenharmony_ci  autoSelectFamilyAttemptTimeout = common.platformTimeout(1500);
171cb0ef41Sopenharmony_ci}
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_cifunction _lookup(resolver, hostname, options, cb) {
201cb0ef41Sopenharmony_ci  resolver.resolve(hostname, 'ANY', (err, replies) => {
211cb0ef41Sopenharmony_ci    assert.notStrictEqual(options.family, 4);
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ci    if (err) {
241cb0ef41Sopenharmony_ci      return cb(err);
251cb0ef41Sopenharmony_ci    }
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci    const hosts = replies
281cb0ef41Sopenharmony_ci      .map((r) => ({ address: r.address, family: r.type === 'AAAA' ? 6 : 4 }))
291cb0ef41Sopenharmony_ci      .sort((a, b) => b.family - a.family);
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci    if (options.all === true) {
321cb0ef41Sopenharmony_ci      return cb(null, hosts);
331cb0ef41Sopenharmony_ci    }
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci    return cb(null, hosts[0].address, hosts[0].family);
361cb0ef41Sopenharmony_ci  });
371cb0ef41Sopenharmony_ci}
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_cifunction createDnsServer(ipv6Addr, ipv4Addr, cb) {
401cb0ef41Sopenharmony_ci  // Create a DNS server which replies with a AAAA and a A record for the same host
411cb0ef41Sopenharmony_ci  const socket = dgram.createSocket('udp4');
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  socket.on('message', common.mustCall((msg, { address, port }) => {
441cb0ef41Sopenharmony_ci    const parsed = parseDNSPacket(msg);
451cb0ef41Sopenharmony_ci    const domain = parsed.questions[0].domain;
461cb0ef41Sopenharmony_ci    assert.strictEqual(domain, 'example.org');
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci    socket.send(writeDNSPacket({
491cb0ef41Sopenharmony_ci      id: parsed.id,
501cb0ef41Sopenharmony_ci      questions: parsed.questions,
511cb0ef41Sopenharmony_ci      answers: [
521cb0ef41Sopenharmony_ci        { type: 'AAAA', address: ipv6Addr, ttl: 123, domain: 'example.org' },
531cb0ef41Sopenharmony_ci        { type: 'A', address: ipv4Addr, ttl: 123, domain: 'example.org' },
541cb0ef41Sopenharmony_ci      ]
551cb0ef41Sopenharmony_ci    }), port, address);
561cb0ef41Sopenharmony_ci  }));
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  socket.bind(0, () => {
591cb0ef41Sopenharmony_ci    const resolver = new Resolver();
601cb0ef41Sopenharmony_ci    resolver.setServers([`127.0.0.1:${socket.address().port}`]);
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci    cb({ dnsServer: socket, lookup: _lookup.bind(null, resolver) });
631cb0ef41Sopenharmony_ci  });
641cb0ef41Sopenharmony_ci}
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci// Test that IPV4 is reached by default if IPV6 is not reachable and the default is enabled
671cb0ef41Sopenharmony_ci{
681cb0ef41Sopenharmony_ci  createDnsServer('::1', '127.0.0.1', common.mustCall(function({ dnsServer, lookup }) {
691cb0ef41Sopenharmony_ci    const ipv4Server = createServer((socket) => {
701cb0ef41Sopenharmony_ci      socket.on('data', common.mustCall(() => {
711cb0ef41Sopenharmony_ci        socket.write('response-ipv4');
721cb0ef41Sopenharmony_ci        socket.end();
731cb0ef41Sopenharmony_ci      }));
741cb0ef41Sopenharmony_ci    });
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci    ipv4Server.listen(0, '127.0.0.1', common.mustCall(() => {
771cb0ef41Sopenharmony_ci      setDefaultAutoSelectFamily(true);
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci      const connection = createConnection({
801cb0ef41Sopenharmony_ci        host: 'example.org',
811cb0ef41Sopenharmony_ci        port: ipv4Server.address().port,
821cb0ef41Sopenharmony_ci        lookup,
831cb0ef41Sopenharmony_ci        autoSelectFamilyAttemptTimeout,
841cb0ef41Sopenharmony_ci      });
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci      let response = '';
871cb0ef41Sopenharmony_ci      connection.setEncoding('utf-8');
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci      connection.on('data', (chunk) => {
901cb0ef41Sopenharmony_ci        response += chunk;
911cb0ef41Sopenharmony_ci      });
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci      connection.on('end', common.mustCall(() => {
941cb0ef41Sopenharmony_ci        assert.strictEqual(response, 'response-ipv4');
951cb0ef41Sopenharmony_ci        ipv4Server.close();
961cb0ef41Sopenharmony_ci        dnsServer.close();
971cb0ef41Sopenharmony_ci      }));
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci      connection.write('request');
1001cb0ef41Sopenharmony_ci    }));
1011cb0ef41Sopenharmony_ci  }));
1021cb0ef41Sopenharmony_ci}
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci// Test that IPV4 is not reached by default if IPV6 is not reachable and the default is disabled
1051cb0ef41Sopenharmony_ci{
1061cb0ef41Sopenharmony_ci  createDnsServer('::1', '127.0.0.1', common.mustCall(function({ dnsServer, lookup }) {
1071cb0ef41Sopenharmony_ci    const ipv4Server = createServer((socket) => {
1081cb0ef41Sopenharmony_ci      socket.on('data', common.mustCall(() => {
1091cb0ef41Sopenharmony_ci        socket.write('response-ipv4');
1101cb0ef41Sopenharmony_ci        socket.end();
1111cb0ef41Sopenharmony_ci      }));
1121cb0ef41Sopenharmony_ci    });
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci    ipv4Server.listen(0, '127.0.0.1', common.mustCall(() => {
1151cb0ef41Sopenharmony_ci      setDefaultAutoSelectFamily(false);
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci      const port = ipv4Server.address().port;
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci      const connection = createConnection({
1201cb0ef41Sopenharmony_ci        host: 'example.org',
1211cb0ef41Sopenharmony_ci        port,
1221cb0ef41Sopenharmony_ci        lookup,
1231cb0ef41Sopenharmony_ci      });
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci      connection.on('ready', common.mustNotCall());
1261cb0ef41Sopenharmony_ci      connection.on('error', common.mustCall((error) => {
1271cb0ef41Sopenharmony_ci        if (common.hasIPv6) {
1281cb0ef41Sopenharmony_ci          assert.strictEqual(error.code, 'ECONNREFUSED');
1291cb0ef41Sopenharmony_ci          assert.strictEqual(error.message, `connect ECONNREFUSED ::1:${port}`);
1301cb0ef41Sopenharmony_ci        } else if (error.code === 'EAFNOSUPPORT') {
1311cb0ef41Sopenharmony_ci          assert.strictEqual(error.message, `connect EAFNOSUPPORT ::1:${port} - Local (undefined:undefined)`);
1321cb0ef41Sopenharmony_ci        } else if (common.isIBMi) {
1331cb0ef41Sopenharmony_ci          // IBMi returns EUNATCH (ERRNO 42) when IPv6 is disabled
1341cb0ef41Sopenharmony_ci          // keep this errno assertion until EUNATCH is recognized by libuv
1351cb0ef41Sopenharmony_ci          assert.strictEqual(error.errno, -42);
1361cb0ef41Sopenharmony_ci        } else {
1371cb0ef41Sopenharmony_ci          assert.strictEqual(error.code, 'EADDRNOTAVAIL');
1381cb0ef41Sopenharmony_ci          assert.strictEqual(error.message, `connect EADDRNOTAVAIL ::1:${port} - Local (:::0)`);
1391cb0ef41Sopenharmony_ci        }
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci        ipv4Server.close();
1421cb0ef41Sopenharmony_ci        dnsServer.close();
1431cb0ef41Sopenharmony_ci      }));
1441cb0ef41Sopenharmony_ci    }));
1451cb0ef41Sopenharmony_ci  }));
1461cb0ef41Sopenharmony_ci}
147