import * as _ from 'lodash' ; import * as dns2 from 'dns2' ; const DNS_SERVER_MAP = { } ; export function getDnsServer ( mockServerPort ) { if ( ! DNS_SERVER_MAP [ mockServerPort ] ) { const serverPromise = ( async ( ) => { const server = new DnsServer ( ) ; server . on ( 'close' , ( ) => { delete DNS_SERVER_MAP [ mockServerPort ] ; } ) ; await server . start ( ) ; return server ; } ) ( ) ; DNS_SERVER_MAP [ mockServerPort ] = serverPromise ; } return DNS_SERVER_MAP [ mockServerPort ] ! ; } export async function stopDnsServer ( mockServerPort ) { const dnsServer = await DNS_SERVER_MAP [ mockServerPort ] ; if ( ! dnsServer ) return ; delete DNS_SERVER_MAP [ mockServerPort ] ; dnsServer . stop ( ) ; } const EMPTY_SET = new Set ( ) ; class DnsServer extends dns2 . UDPServer { constructor ( ) { super ( ( req , sendResponse ) => this . handleQuery ( req , sendResponse ) ) ; } private hosts : { [ host ] : ReadonlySet < string > | undefined ; } = { } ; setHosts ( hosts ) { this . hosts = hosts ; } private getHostAddresses ( hostname ) { return this . hosts [ hostname ] ?? EMPTY_SET ; } handleQuery ( request , sendResponse ) { const response = dns2 . Packet . createResponseFromRequest ( request ) ; const [ question ] = request . questions ; const answers = this . getHostAddresses ( question . name ) ; if ( answers . size > 1 ) { console . log ( `Multiple hosts in internal DNS for hostname ${ question . name }:` , answers ) ; } if ( answers ) { answers . forEach ( ( answer ) => { response . answers . push ( { name : question . name , type : dns2 . Packet . TYPE . A , class : dns2 . Packet . CLASS . IN , ttl : 0 , address : answer } ) ; } ) ; } sendResponse ( response ) ; } start ( ) { return new Promise < void > ( ( resolve , reject ) => { this . listen ( 0 , '127.0.0.1' ) ; this . once ( 'listening' , ( ) => resolve ( ) ) ; this . once ( 'error' , reject ) ; } ) ; } stop ( ) { return new Promise < void > ( ( resolve ) => { this . once ( 'close' , resolve ) ; this . close ( ) ; } ) ; } }