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
						
					
					
				"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
 |