You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					117 lines
				
				3.6 KiB
			
		
		
			
		
	
	
					117 lines
				
				3.6 KiB
			| 
											3 years ago
										 | "use strict"; | ||
|  | Object.defineProperty(exports, "__esModule", { value: true }); | ||
|  | exports.SrvPoller = exports.SrvPollingEvent = void 0; | ||
|  | const dns = require("dns"); | ||
|  | const timers_1 = require("timers"); | ||
|  | const error_1 = require("../error"); | ||
|  | const mongo_types_1 = require("../mongo_types"); | ||
|  | const utils_1 = require("../utils"); | ||
|  | /** | ||
|  |  * Determines whether a provided address matches the provided parent domain in order | ||
|  |  * to avoid certain attack vectors. | ||
|  |  * | ||
|  |  * @param srvAddress - The address to check against a domain | ||
|  |  * @param parentDomain - The domain to check the provided address against | ||
|  |  * @returns Whether the provided address matches the parent domain | ||
|  |  */ | ||
|  | function matchesParentDomain(srvAddress, parentDomain) { | ||
|  |     const regex = /^.*?\./; | ||
|  |     const srv = `.${srvAddress.replace(regex, '')}`; | ||
|  |     const parent = `.${parentDomain.replace(regex, '')}`; | ||
|  |     return srv.endsWith(parent); | ||
|  | } | ||
|  | /** | ||
|  |  * @internal | ||
|  |  * @category Event | ||
|  |  */ | ||
|  | class SrvPollingEvent { | ||
|  |     constructor(srvRecords) { | ||
|  |         this.srvRecords = srvRecords; | ||
|  |     } | ||
|  |     hostnames() { | ||
|  |         return new Set(this.srvRecords.map(r => utils_1.HostAddress.fromSrvRecord(r).toString())); | ||
|  |     } | ||
|  | } | ||
|  | exports.SrvPollingEvent = SrvPollingEvent; | ||
|  | /** @internal */ | ||
|  | class SrvPoller extends mongo_types_1.TypedEventEmitter { | ||
|  |     constructor(options) { | ||
|  |         super(); | ||
|  |         if (!options || !options.srvHost) { | ||
|  |             throw new error_1.MongoRuntimeError('Options for SrvPoller must exist and include srvHost'); | ||
|  |         } | ||
|  |         this.srvHost = options.srvHost; | ||
|  |         this.srvMaxHosts = options.srvMaxHosts ?? 0; | ||
|  |         this.srvServiceName = options.srvServiceName ?? 'mongodb'; | ||
|  |         this.rescanSrvIntervalMS = 60000; | ||
|  |         this.heartbeatFrequencyMS = options.heartbeatFrequencyMS ?? 10000; | ||
|  |         this.haMode = false; | ||
|  |         this.generation = 0; | ||
|  |         this._timeout = undefined; | ||
|  |     } | ||
|  |     get srvAddress() { | ||
|  |         return `_${this.srvServiceName}._tcp.${this.srvHost}`; | ||
|  |     } | ||
|  |     get intervalMS() { | ||
|  |         return this.haMode ? this.heartbeatFrequencyMS : this.rescanSrvIntervalMS; | ||
|  |     } | ||
|  |     start() { | ||
|  |         if (!this._timeout) { | ||
|  |             this.schedule(); | ||
|  |         } | ||
|  |     } | ||
|  |     stop() { | ||
|  |         if (this._timeout) { | ||
|  |             (0, timers_1.clearTimeout)(this._timeout); | ||
|  |             this.generation += 1; | ||
|  |             this._timeout = undefined; | ||
|  |         } | ||
|  |     } | ||
|  |     // TODO(NODE-4994): implement new logging logic for SrvPoller failures
 | ||
|  |     schedule() { | ||
|  |         if (this._timeout) { | ||
|  |             (0, timers_1.clearTimeout)(this._timeout); | ||
|  |         } | ||
|  |         this._timeout = (0, timers_1.setTimeout)(() => { | ||
|  |             this._poll().catch(() => null); | ||
|  |         }, this.intervalMS); | ||
|  |     } | ||
|  |     success(srvRecords) { | ||
|  |         this.haMode = false; | ||
|  |         this.schedule(); | ||
|  |         this.emit(SrvPoller.SRV_RECORD_DISCOVERY, new SrvPollingEvent(srvRecords)); | ||
|  |     } | ||
|  |     failure() { | ||
|  |         this.haMode = true; | ||
|  |         this.schedule(); | ||
|  |     } | ||
|  |     async _poll() { | ||
|  |         const generation = this.generation; | ||
|  |         let srvRecords; | ||
|  |         try { | ||
|  |             srvRecords = await dns.promises.resolveSrv(this.srvAddress); | ||
|  |         } | ||
|  |         catch (dnsError) { | ||
|  |             this.failure(); | ||
|  |             return; | ||
|  |         } | ||
|  |         if (generation !== this.generation) { | ||
|  |             return; | ||
|  |         } | ||
|  |         const finalAddresses = []; | ||
|  |         for (const record of srvRecords) { | ||
|  |             if (matchesParentDomain(record.name, this.srvHost)) { | ||
|  |                 finalAddresses.push(record); | ||
|  |             } | ||
|  |         } | ||
|  |         if (!finalAddresses.length) { | ||
|  |             this.failure(); | ||
|  |             return; | ||
|  |         } | ||
|  |         this.success(finalAddresses); | ||
|  |     } | ||
|  | } | ||
|  | exports.SrvPoller = SrvPoller; | ||
|  | /** @event */ | ||
|  | SrvPoller.SRV_RECORD_DISCOVERY = 'srvRecordDiscovery'; | ||
|  | //# sourceMappingURL=srv_polling.js.map
 |