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