srv_polling.js 4.0 KB

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