Skip to content

Commit e3c515e

Browse files
committed
fix: filter out duplicate dns results
1 parent 12992e7 commit e3c515e

File tree

2 files changed

+91
-7
lines changed

2 files changed

+91
-7
lines changed

src/rfc-8252-http-server.spec.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type { SinonSandbox } from 'sinon';
99
import sinon from 'sinon';
1010
import { promisify } from 'util';
1111
import { randomBytes } from 'crypto';
12+
import { promises as dns } from 'dns';
1213

1314
// node-fetch@3 is ESM-only...
1415
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
@@ -485,4 +486,71 @@ describe('RFC8252HTTPServer', function () {
485486
});
486487
});
487488
});
489+
490+
context('with dns duplicates', function () {
491+
const originalDnsLookup = dns.lookup;
492+
let dnsLookupStub: sinon.SinonStub;
493+
494+
this.beforeEach(function () {
495+
dnsLookupStub = sinon.stub();
496+
dns.lookup = dnsLookupStub;
497+
});
498+
499+
this.afterEach(function () {
500+
dns.lookup = originalDnsLookup;
501+
});
502+
503+
it('only filters exact duplicates', async function () {
504+
dnsLookupStub.resolves([
505+
{ address: '127.0.0.1', family: 4 },
506+
{ address: '127.0.0.1', family: 4 },
507+
{ address: '[::1]', family: 6 },
508+
{ address: '[::1]', family: 6 },
509+
]);
510+
511+
const interfaces = await RFC8252HTTPServer['_getAllInterfaces'].call(
512+
'localhost'
513+
);
514+
515+
expect(interfaces).to.have.lengthOf(2);
516+
expect(interfaces[0].address).to.equal('127.0.0.1');
517+
expect(interfaces[1].address).to.equal('[::1]');
518+
expect(interfaces[0].family).to.equal(4);
519+
expect(interfaces[1].family).to.equal(6);
520+
});
521+
522+
it('keeps same addresses, different family', async function () {
523+
dnsLookupStub.resolves([
524+
{ address: '127.0.0.1', family: 4 },
525+
{ address: '127.0.0.1', family: 6 },
526+
]);
527+
528+
const interfaces = await RFC8252HTTPServer['_getAllInterfaces'].call(
529+
'localhost'
530+
);
531+
532+
expect(interfaces).to.have.lengthOf(2);
533+
expect(interfaces[0].address).to.equal('127.0.0.1');
534+
expect(interfaces[1].address).to.equal('127.0.0.1');
535+
expect(interfaces[0].family).to.equal(4);
536+
expect(interfaces[1].family).to.equal(6);
537+
});
538+
539+
it('keeps same familes, different address', async function () {
540+
dnsLookupStub.resolves([
541+
{ address: '127.0.0.1', family: 4 },
542+
{ address: '192.168.1.15', family: 4 },
543+
]);
544+
545+
const interfaces = await RFC8252HTTPServer['_getAllInterfaces'].call(
546+
'localhost'
547+
);
548+
549+
expect(interfaces).to.have.lengthOf(2);
550+
expect(interfaces[0].address).to.equal('127.0.0.1');
551+
expect(interfaces[1].address).to.equal('192.168.1.15');
552+
expect(interfaces[0].family).to.equal(4);
553+
expect(interfaces[1].family).to.equal(4);
554+
});
555+
});
488556
});

src/rfc-8252-http-server.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,25 @@ export class RFC8252HTTPServer {
272272
});
273273
};
274274

275+
private static async _getAllInterfaces(
276+
hostname: string
277+
): Promise<{ address: string; family: number }[]> {
278+
const dnsResults = await dns.lookup(hostname, {
279+
all: true,
280+
hints: ADDRCONFIG,
281+
});
282+
283+
return dnsResults
284+
.filter(
285+
(dns, index, arr) =>
286+
arr.findIndex(
287+
(otherDns) =>
288+
dns.address === otherDns.address && dns.family === otherDns.family
289+
) === index
290+
)
291+
.map(({ address, family }) => ({ address, family }));
292+
}
293+
275294
/**
276295
* Add a redirect from a local URL served on the server to an external URL.
277296
*/
@@ -368,14 +387,11 @@ export class RFC8252HTTPServer {
368387
// to do what Node.js does by default when only a host is provided,
369388
// namely listening on all interfaces.
370389
let hostname = this.redirectUrl.hostname;
371-
if (hostname.startsWith('[') && hostname.endsWith(']'))
390+
if (hostname.startsWith('[') && hostname.endsWith(']')) {
372391
hostname = hostname.slice(1, -1);
373-
const dnsResults = (
374-
await dns.lookup(hostname, {
375-
all: true,
376-
hints: ADDRCONFIG,
377-
})
378-
).map(({ address, family }) => ({ address, family }));
392+
}
393+
394+
const dnsResults = await RFC8252HTTPServer._getAllInterfaces(hostname);
379395

380396
this.logger.emit('mongodb-oidc-plugin:local-listen-resolved-hostname', {
381397
url: this.redirectUrl.toString(),

0 commit comments

Comments
 (0)