11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci// Flags: --enable-network-family-autoselection
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ciconst common = require('../common');
61cb0ef41Sopenharmony_ciconst { parseDNSPacket, writeDNSPacket } = require('../common/dns');
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ciconst assert = require('assert');
91cb0ef41Sopenharmony_ciconst dgram = require('dgram');
101cb0ef41Sopenharmony_ciconst { Resolver } = require('dns');
111cb0ef41Sopenharmony_ciconst { createConnection, createServer, setDefaultAutoSelectFamilyAttemptTimeout } = require('net');
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ci// Test that happy eyeballs algorithm can be enable from command line.
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ci// Some of the windows machines in the CI need more time to establish connection
161cb0ef41Sopenharmony_cisetDefaultAutoSelectFamilyAttemptTimeout(common.platformTimeout(common.isWindows ? 1500 : 250));
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_cifunction _lookup(resolver, hostname, options, cb) {
191cb0ef41Sopenharmony_ci  resolver.resolve(hostname, 'ANY', (err, replies) => {
201cb0ef41Sopenharmony_ci    assert.notStrictEqual(options.family, 4);
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci    if (err) {
231cb0ef41Sopenharmony_ci      return cb(err);
241cb0ef41Sopenharmony_ci    }
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci    const hosts = replies
271cb0ef41Sopenharmony_ci      .map((r) => ({ address: r.address, family: r.type === 'AAAA' ? 6 : 4 }))
281cb0ef41Sopenharmony_ci      .sort((a, b) => b.family - a.family);
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci    if (options.all === true) {
311cb0ef41Sopenharmony_ci      return cb(null, hosts);
321cb0ef41Sopenharmony_ci    }
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci    return cb(null, hosts[0].address, hosts[0].family);
351cb0ef41Sopenharmony_ci  });
361cb0ef41Sopenharmony_ci}
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_cifunction createDnsServer(ipv6Addr, ipv4Addr, cb) {
391cb0ef41Sopenharmony_ci  // Create a DNS server which replies with a AAAA and a A record for the same host
401cb0ef41Sopenharmony_ci  const socket = dgram.createSocket('udp4');
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci  socket.on('message', common.mustCall((msg, { address, port }) => {
431cb0ef41Sopenharmony_ci    const parsed = parseDNSPacket(msg);
441cb0ef41Sopenharmony_ci    const domain = parsed.questions[0].domain;
451cb0ef41Sopenharmony_ci    assert.strictEqual(domain, 'example.org');
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci    socket.send(writeDNSPacket({
481cb0ef41Sopenharmony_ci      id: parsed.id,
491cb0ef41Sopenharmony_ci      questions: parsed.questions,
501cb0ef41Sopenharmony_ci      answers: [
511cb0ef41Sopenharmony_ci        { type: 'AAAA', address: ipv6Addr, ttl: 123, domain: 'example.org' },
521cb0ef41Sopenharmony_ci        { type: 'A', address: ipv4Addr, ttl: 123, domain: 'example.org' },
531cb0ef41Sopenharmony_ci      ]
541cb0ef41Sopenharmony_ci    }), port, address);
551cb0ef41Sopenharmony_ci  }));
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci  socket.bind(0, () => {
581cb0ef41Sopenharmony_ci    const resolver = new Resolver();
591cb0ef41Sopenharmony_ci    resolver.setServers([`127.0.0.1:${socket.address().port}`]);
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci    cb({ dnsServer: socket, lookup: _lookup.bind(null, resolver) });
621cb0ef41Sopenharmony_ci  });
631cb0ef41Sopenharmony_ci}
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci// Test that IPV4 is reached if IPV6 is not reachable
661cb0ef41Sopenharmony_ci{
671cb0ef41Sopenharmony_ci  createDnsServer('::1', '127.0.0.1', common.mustCall(function({ dnsServer, lookup }) {
681cb0ef41Sopenharmony_ci    const ipv4Server = createServer((socket) => {
691cb0ef41Sopenharmony_ci      socket.on('data', common.mustCall(() => {
701cb0ef41Sopenharmony_ci        socket.write('response-ipv4');
711cb0ef41Sopenharmony_ci        socket.end();
721cb0ef41Sopenharmony_ci      }));
731cb0ef41Sopenharmony_ci    });
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci    ipv4Server.listen(0, '127.0.0.1', common.mustCall(() => {
761cb0ef41Sopenharmony_ci      const port = ipv4Server.address().port;
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci      const connection = createConnection({
791cb0ef41Sopenharmony_ci        host: 'example.org',
801cb0ef41Sopenharmony_ci        port: port,
811cb0ef41Sopenharmony_ci        lookup,
821cb0ef41Sopenharmony_ci      });
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci      let response = '';
851cb0ef41Sopenharmony_ci      connection.setEncoding('utf-8');
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci      connection.on('ready', common.mustCall(() => {
881cb0ef41Sopenharmony_ci        assert.deepStrictEqual(connection.autoSelectFamilyAttemptedAddresses, [`::1:${port}`, `127.0.0.1:${port}`]);
891cb0ef41Sopenharmony_ci      }));
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci      connection.on('data', (chunk) => {
921cb0ef41Sopenharmony_ci        response += chunk;
931cb0ef41Sopenharmony_ci      });
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci      connection.on('end', common.mustCall(() => {
961cb0ef41Sopenharmony_ci        assert.strictEqual(response, 'response-ipv4');
971cb0ef41Sopenharmony_ci        ipv4Server.close();
981cb0ef41Sopenharmony_ci        dnsServer.close();
991cb0ef41Sopenharmony_ci      }));
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci      connection.write('request');
1021cb0ef41Sopenharmony_ci    }));
1031cb0ef41Sopenharmony_ci  }));
1041cb0ef41Sopenharmony_ci}
105