srv_polling.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.SrvPoller = exports.SrvPollingEvent = void 0;
  4. const dns = require("dns");
  5. const timers_1 = require("timers");
  6. const error_1 = require("../error");
  7. const logger_1 = require("../logger");
  8. const mongo_types_1 = require("../mongo_types");
  9. const utils_1 = require("../utils");
  10. /**
  11. * Determines whether a provided address matches the provided parent domain in order
  12. * to avoid certain attack vectors.
  13. *
  14. * @param srvAddress - The address to check against a domain
  15. * @param parentDomain - The domain to check the provided address against
  16. * @returns Whether the provided address matches the parent domain
  17. */
  18. function matchesParentDomain(srvAddress, parentDomain) {
  19. const regex = /^.*?\./;
  20. const srv = `.${srvAddress.replace(regex, '')}`;
  21. const parent = `.${parentDomain.replace(regex, '')}`;
  22. return srv.endsWith(parent);
  23. }
  24. /**
  25. * @internal
  26. * @category Event
  27. */
  28. class SrvPollingEvent {
  29. constructor(srvRecords) {
  30. this.srvRecords = srvRecords;
  31. }
  32. hostnames() {
  33. return new Set(this.srvRecords.map(r => utils_1.HostAddress.fromSrvRecord(r).toString()));
  34. }
  35. }
  36. exports.SrvPollingEvent = SrvPollingEvent;
  37. /** @internal */
  38. class SrvPoller extends mongo_types_1.TypedEventEmitter {
  39. constructor(options) {
  40. var _a, _b, _c;
  41. super();
  42. if (!options || !options.srvHost) {
  43. throw new error_1.MongoRuntimeError('Options for SrvPoller must exist and include srvHost');
  44. }
  45. this.srvHost = options.srvHost;
  46. this.srvMaxHosts = (_a = options.srvMaxHosts) !== null && _a !== void 0 ? _a : 0;
  47. this.srvServiceName = (_b = options.srvServiceName) !== null && _b !== void 0 ? _b : 'mongodb';
  48. this.rescanSrvIntervalMS = 60000;
  49. this.heartbeatFrequencyMS = (_c = options.heartbeatFrequencyMS) !== null && _c !== void 0 ? _c : 10000;
  50. this.logger = new logger_1.Logger('srvPoller', options);
  51. this.haMode = false;
  52. this.generation = 0;
  53. this._timeout = undefined;
  54. }
  55. get srvAddress() {
  56. return `_${this.srvServiceName}._tcp.${this.srvHost}`;
  57. }
  58. get intervalMS() {
  59. return this.haMode ? this.heartbeatFrequencyMS : this.rescanSrvIntervalMS;
  60. }
  61. start() {
  62. if (!this._timeout) {
  63. this.schedule();
  64. }
  65. }
  66. stop() {
  67. if (this._timeout) {
  68. clearTimeout(this._timeout);
  69. this.generation += 1;
  70. this._timeout = undefined;
  71. }
  72. }
  73. schedule() {
  74. if (this._timeout) {
  75. clearTimeout(this._timeout);
  76. }
  77. this._timeout = (0, timers_1.setTimeout)(() => this._poll(), this.intervalMS);
  78. }
  79. success(srvRecords) {
  80. this.haMode = false;
  81. this.schedule();
  82. this.emit(SrvPoller.SRV_RECORD_DISCOVERY, new SrvPollingEvent(srvRecords));
  83. }
  84. failure(message, obj) {
  85. this.logger.warn(message, obj);
  86. this.haMode = true;
  87. this.schedule();
  88. }
  89. parentDomainMismatch(srvRecord) {
  90. this.logger.warn(`parent domain mismatch on SRV record (${srvRecord.name}:${srvRecord.port})`, srvRecord);
  91. }
  92. _poll() {
  93. const generation = this.generation;
  94. dns.resolveSrv(this.srvAddress, (err, srvRecords) => {
  95. if (generation !== this.generation) {
  96. return;
  97. }
  98. if (err) {
  99. this.failure('DNS error', err);
  100. return;
  101. }
  102. const finalAddresses = [];
  103. for (const record of srvRecords) {
  104. if (matchesParentDomain(record.name, this.srvHost)) {
  105. finalAddresses.push(record);
  106. }
  107. else {
  108. this.parentDomainMismatch(record);
  109. }
  110. }
  111. if (!finalAddresses.length) {
  112. this.failure('No valid addresses found at host');
  113. return;
  114. }
  115. this.success(finalAddresses);
  116. });
  117. }
  118. }
  119. exports.SrvPoller = SrvPoller;
  120. /** @event */
  121. SrvPoller.SRV_RECORD_DISCOVERY = 'srvRecordDiscovery';
  122. //# sourceMappingURL=srv_polling.js.map