From e17698f950af83bf2b3edc540d2a3e1fb73cba59 Mon Sep 17 00:00:00 2001 From: Yaroslav Admin Date: Tue, 10 May 2022 20:35:56 +0200 Subject: [PATCH] fix: prefer IPv4 addresses when resolving domains Node 17+ changed the DNS resolution (see https://github.com/nodejs/node/issues/40702), so now it resolves `localhost` according to the OS settings instead of IPv4-address first. The Karma server only listens on IPv4 address (127.0.0.1) by default, but the requests are sent to `localhost` in several places and `localhost` is resolved into IPv6 address (`::`) in Node 17+. So the run/stop/proxy request is unable to reach the Karma server and produces an error. This commit configures karma to use the IPv4-address first approach in newer Node version as well. In the future major release, we may consider changing defaults to listen on IPv6 address instead, but IPv6 is not supported in Docker on macOS and Windows, so I think we should not rush such a change to make sure karma works there out of the box. Fixes #3730 --- lib/middleware/proxy.js | 6 +++++- lib/runner.js | 4 +++- lib/stopper.js | 4 +++- lib/utils/dns-utils.js | 11 +++++++++++ test/e2e/support/proxy.js | 2 +- 5 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 lib/utils/dns-utils.js diff --git a/lib/middleware/proxy.js b/lib/middleware/proxy.js index 6b0fcf730..b2e0e7f63 100644 --- a/lib/middleware/proxy.js +++ b/lib/middleware/proxy.js @@ -3,6 +3,7 @@ const { Agent: httpAgent } = require('http') const { Agent: httpsAgent } = require('https') const httpProxy = require('http-proxy') const _ = require('lodash') +const { lookup } = require('../utils/dns-utils') const log = require('../logger').create('proxy') @@ -41,7 +42,10 @@ function parseProxyConfig (proxies, config) { const port = proxyDetails.port || defaultPorts[proxyDetails.protocol] || config.port const changeOrigin = proxyConfiguration.changeOrigin || false const Agent = protocol === 'https:' ? httpsAgent : httpAgent - const agent = new Agent({ keepAlive: true }) + const agent = new Agent({ + keepAlive: true, + lookup + }) const proxy = httpProxy.createProxyServer({ target: { host: hostname, port, protocol }, xfwd: true, diff --git a/lib/runner.js b/lib/runner.js index 2e04065b6..fb67ebe92 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -7,6 +7,7 @@ const EventEmitter = require('events').EventEmitter const helper = require('./helper') const cfg = require('./config') const logger = require('./logger') +const { lookup } = require('./utils/dns-utils') const log = logger.create('runner') function parseExitCode (buffer, defaultExitCode, failOnEmptyTestSuite) { @@ -74,7 +75,8 @@ function run (cliOptionsOrConfig, done) { method: 'POST', headers: { 'Content-Type': 'application/json' - } + }, + lookup } const request = http.request(options, function (response) { diff --git a/lib/stopper.js b/lib/stopper.js index 964eb5e37..386fa5d83 100644 --- a/lib/stopper.js +++ b/lib/stopper.js @@ -2,6 +2,7 @@ const http = require('http') const cfg = require('./config') const logger = require('./logger') const helper = require('./helper') +const { lookup } = require('./utils/dns-utils') exports.stop = function (cliOptionsOrConfig, done) { cliOptionsOrConfig = cliOptionsOrConfig || {} @@ -42,7 +43,8 @@ exports.stop = function (cliOptionsOrConfig, done) { hostname: config.hostname, path: config.urlRoot + 'stop', port: config.port, - method: 'GET' + method: 'GET', + lookup }) request.on('response', function (response) { diff --git a/lib/utils/dns-utils.js b/lib/utils/dns-utils.js new file mode 100644 index 000000000..5d281ed6f --- /dev/null +++ b/lib/utils/dns-utils.js @@ -0,0 +1,11 @@ +const dns = require('dns') + +// Node >=17 has different DNS resolution (see +// https://github.com/nodejs/node/issues/40702), it resolves domains +// according to the OS settings instead of IPv4-address first. The Karma server +// only listens on IPv4 address (127.0.0.1) by default, but the requests are +// sent to `localhost` in several places and `localhost` is resolved into IPv6 +// address (`::`). So the run/stop/proxy request is unable to reach the Karma +// server and produces an error. To mitigate this issue karma force the +// IPv4-address first approach in Node >=17 as well. +module.exports.lookup = (hostname, options, callback) => dns.lookup(hostname, { ...options, verbatim: false }, callback) diff --git a/test/e2e/support/proxy.js b/test/e2e/support/proxy.js index 5bf17c1fd..e78a4544c 100644 --- a/test/e2e/support/proxy.js +++ b/test/e2e/support/proxy.js @@ -8,7 +8,7 @@ module.exports = class Proxy { this.proxyPathRegExp = null this.proxy = httpProxy.createProxyServer({ - target: 'http://localhost:9876' + target: 'http://127.0.0.1:9876' }) this.proxy.on('error', (err) => {