Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion src/rfc-8252-http-server.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { RFC8252HTTPServer } from './rfc-8252-http-server';
import { getAllInterfaces, RFC8252HTTPServer } from './rfc-8252-http-server';
import { expect } from 'chai';
import type { Server as HTTPServer } from 'http';
import { createServer as createHTTPServer } from 'http';
Expand Down Expand Up @@ -485,4 +485,58 @@ describe('RFC8252HTTPServer', function () {
});
});
});

context('getAllInterfaces', function () {
let dnsLookupStub: sinon.SinonStub;
this.beforeEach(function () {
dnsLookupStub = sinon.stub();
});

it('filters out exact duplicates', async function () {
dnsLookupStub.resolves([
{ address: '127.0.0.1', family: 4 },
{ address: '127.0.0.1', family: 4 },
{ address: '[::1]', family: 6 },
{ address: '[::1]', family: 6 },
]);

const interfaces = await getAllInterfaces('localhost', dnsLookupStub);

expect(interfaces).to.have.lengthOf(2);
expect(interfaces[0].address).to.equal('127.0.0.1');
expect(interfaces[1].address).to.equal('[::1]');
expect(interfaces[0].family).to.equal(4);
expect(interfaces[1].family).to.equal(6);
});

it('keeps same addresses, different family', async function () {
dnsLookupStub.resolves([
{ address: '127.0.0.1', family: 4 },
{ address: '127.0.0.1', family: 6 },
]);

const interfaces = await getAllInterfaces('localhost', dnsLookupStub);

expect(interfaces).to.have.lengthOf(2);
expect(interfaces[0].address).to.equal('127.0.0.1');
expect(interfaces[1].address).to.equal('127.0.0.1');
expect(interfaces[0].family).to.equal(4);
expect(interfaces[1].family).to.equal(6);
});

it('keeps same familes, different address', async function () {
dnsLookupStub.resolves([
{ address: '127.0.0.1', family: 4 },
{ address: '192.168.1.15', family: 4 },
]);

const interfaces = await getAllInterfaces('localhost', dnsLookupStub);

expect(interfaces).to.have.lengthOf(2);
expect(interfaces[0].address).to.equal('127.0.0.1');
expect(interfaces[1].address).to.equal('192.168.1.15');
expect(interfaces[0].family).to.equal(4);
expect(interfaces[1].family).to.equal(4);
});
});
});
31 changes: 24 additions & 7 deletions src/rfc-8252-http-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,26 @@ export interface RFC8252HTTPServerOptions {
redirectServerRequestHandler?: RedirectServerRequestHandler;
}

export async function getAllInterfaces(
hostname: string,
lookup: typeof dns.lookup = dns.lookup
): Promise<{ address: string; family: number }[]> {
const dnsResults = await lookup(hostname, {
all: true,
hints: ADDRCONFIG,
});

return dnsResults
.filter(
(dns, index, arr) =>
arr.findIndex(
(otherDns) =>
dns.address === otherDns.address && dns.family === otherDns.family
) === index
)
.map(({ address, family }) => ({ address, family }));
}

/** @internal */
export class RFC8252HTTPServer {
private readonly redirectUrl: URL;
Expand Down Expand Up @@ -368,14 +388,11 @@ export class RFC8252HTTPServer {
// to do what Node.js does by default when only a host is provided,
// namely listening on all interfaces.
let hostname = this.redirectUrl.hostname;
if (hostname.startsWith('[') && hostname.endsWith(']'))
if (hostname.startsWith('[') && hostname.endsWith(']')) {
hostname = hostname.slice(1, -1);
const dnsResults = (
await dns.lookup(hostname, {
all: true,
hints: ADDRCONFIG,
})
).map(({ address, family }) => ({ address, family }));
}

const dnsResults = await getAllInterfaces(hostname);

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