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
							 |