From f2b740f6ceb190ae3a9ee092895397fa18c1b6c9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Mar 2020 10:15:22 -0800 Subject: [PATCH] grpc-js: Always return IPv6 addresses from DNS resolver --- packages/grpc-js/src/resolver-dns.ts | 16 +---- packages/grpc-js/test/test-resolver.ts | 88 ++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 21 deletions(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 7c51425c..ebfd16dc 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -21,7 +21,6 @@ import { registerDefaultResolver, } from './resolver'; import * as dns from 'dns'; -import * as semver from 'semver'; import * as util from 'util'; import { extractAndSelectServiceConfig, ServiceConfig } from './service-config'; import { ServiceError } from './call'; @@ -70,14 +69,6 @@ const DNS_REGEX = /^(?:dns:)?(?:\/\/(?:[a-zA-Z0-9-]+\.?)+\/)?((?:[a-zA-Z0-9-]+\. */ const DEFAULT_PORT = '443'; -/** - * The range of Node versions in which the Node issue - * https://github.com/nodejs/node/issues/28216 has been fixed. In other - * versions, IPv6 literal addresses cannot be used to establish HTTP/2 - * connections. - */ -const IPV6_SUPPORT_RANGE = '>= 12.6'; - /** * Get a promise that always resolves with either the result of the function * or the error if it failed. @@ -226,12 +217,7 @@ class DnsResolver implements Resolver { const ip4Addresses: dns.LookupAddress[] = addressList.filter( addr => addr.family === 4 ); - let ip6Addresses: dns.LookupAddress[]; - if (semver.satisfies(process.version, IPV6_SUPPORT_RANGE)) { - ip6Addresses = addressList.filter(addr => addr.family === 6); - } else { - ip6Addresses = []; - } + const ip6Addresses: dns.LookupAddress[] = addressList.filter(addr => addr.family === 6); const allAddresses: TcpSubchannelAddress[] = mergeArrays( ip4Addresses, ip6Addresses diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index ebb4d567..21007a3d 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -46,7 +46,14 @@ describe('Name Resolver', () => { addr.port === 50051 ) ); - // We would check for the IPv6 address but it needs to be omitted on some Node versions + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 50051 + ) + ); done(); }, onError: (error: StatusObject) => { @@ -72,7 +79,14 @@ describe('Name Resolver', () => { addr.port === 443 ) ); - // We would check for the IPv6 address but it needs to be omitted on some Node versions + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 443 + ) + ); done(); }, onError: (error: StatusObject) => { @@ -98,7 +112,6 @@ describe('Name Resolver', () => { addr.port === 443 ) ); - // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, onError: (error: StatusObject) => { @@ -124,7 +137,6 @@ describe('Name Resolver', () => { addr.port === 443 ) ); - // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, onError: (error: StatusObject) => { @@ -150,7 +162,6 @@ describe('Name Resolver', () => { addr.port === 50051 ) ); - // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, onError: (error: StatusObject) => { @@ -186,7 +197,72 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.length > 0); + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '127.0.0.1' && + addr.port === 443 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener); + resolver.updateResolution(); + }); + it('Should resolve a DNS name to an IPv6 address', done => { + const target = 'loopback6.unittest.grpc.io'; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 443 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener); + resolver.updateResolution(); + }); + it('Should resolve a DNS name to IPv4 and IPv6 addresses', done => { + const target = 'loopback46.unittest.grpc.io'; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '127.0.0.1' && + addr.port === 443 + ) + ); + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 443 + ) + ); done(); }, onError: (error: StatusObject) => {