|
| 1 | +# Initial DNS Seedlist Discovery |
| 2 | + |
| 3 | +- Status: Accepted |
| 4 | +- Minimum Server Version: N/A |
| 5 | + |
| 6 | +______________________________________________________________________ |
| 7 | + |
| 8 | +## Abstract |
| 9 | + |
| 10 | +Presently, seeding a driver with an initial list of ReplicaSet or MongoS addresses is somewhat cumbersome, requiring a |
| 11 | +comma-delimited list of host names to attempt connections to. A standardized answer to this problem exists in the form |
| 12 | +of SRV records, which allow administrators to configure a single SRV record to return a list of host names. Supporting |
| 13 | +this feature would assist our users by decreasing maintenance load, primarily by removing the need to maintain seed |
| 14 | +lists at an application level. |
| 15 | + |
| 16 | +This specification builds on the [Connection String](../connection-string/connection-string-spec.md) specification. It |
| 17 | +adds a new protocol scheme and modifies how the |
| 18 | +[Host Information](../connection-string/connection-string-spec.md#host-information) is interpreted. |
| 19 | + |
| 20 | +## META |
| 21 | + |
| 22 | +The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and |
| 23 | +"OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt). |
| 24 | + |
| 25 | +## Specification |
| 26 | + |
| 27 | +### Connection String Format |
| 28 | + |
| 29 | +The connection string parser in the driver is extended with a new protocol `mongodb+srv` as a logical pre-processing |
| 30 | +step before it considers the connection string and SDAM specifications. In this protocol, the comma separated list of |
| 31 | +host names is replaced with a single host name. The format is: |
| 32 | + |
| 33 | +``` |
| 34 | +mongodb+srv://{hostname}/{options} |
| 35 | +``` |
| 36 | + |
| 37 | +`{options}` refers to the optional elements from the [Connection String](../connection-string/connection-string-spec.md) |
| 38 | +specification following the `Host Information`. This includes the `Auth database` and `Connection Options`. |
| 39 | + |
| 40 | +For the purposes of this document, `{hostname}` will be divided using the following terminology. If an SRV `{hostname}` |
| 41 | +has: |
| 42 | + |
| 43 | +1. Three or more `.` separated parts, then the left-most part is the `{subdomain}` and the remaining portion is the |
| 44 | + `{domainname}`. |
| 45 | + |
| 46 | + - Examples: |
| 47 | + - `{hostname}` = `cluster_1.tests.mongodb.co.uk` |
| 48 | + |
| 49 | + - `{subdomain}` = `cluster_1` |
| 50 | + - `{domainname}` = `tests.mongodb.co.uk` |
| 51 | + |
| 52 | + - `{hostname}` = `hosts_34.example.com` |
| 53 | + |
| 54 | + - `{subdomain}` = `hosts_34` |
| 55 | + - `{domainname}` = `example.com` |
| 56 | + |
| 57 | +2. One or two `.` separated part(s), then the `{hostname}` is equivalent to the `{domainname}`, and there is no |
| 58 | + subdomain. |
| 59 | + |
| 60 | + - Examples: |
| 61 | + - `{hostname}` = `{domainname}` = `localhost` |
| 62 | + - `{hostname}` = `{domainname}` = `mongodb.local` |
| 63 | + |
| 64 | +Only `{domainname}` is used during SRV record verification and `{subdomain}` is ignored. |
| 65 | + |
| 66 | +### MongoClient Configuration |
| 67 | + |
| 68 | +#### srvMaxHosts |
| 69 | + |
| 70 | +This option is used to limit the number of mongos connections that may be created for sharded topologies. This option |
| 71 | +limits the number of SRV records used to populate the seedlist during initial discovery, as well as the number of |
| 72 | +additional hosts that may be added during |
| 73 | +[SRV polling](../polling-srv-records-for-mongos-discovery/polling-srv-records-for-mongos-discovery.md). This option |
| 74 | +requires a non-negative integer and defaults to zero (i.e. no limit). This option MUST only be configurable at the level |
| 75 | +of a `MongoClient`. |
| 76 | + |
| 77 | +#### srvServiceName |
| 78 | + |
| 79 | +This option specifies a valid SRV service name according to |
| 80 | +[RFC 6335](https://datatracker.ietf.org/doc/html/rfc6335#section-5.1), with the exception that it may exceed 15 |
| 81 | +characters as long as the 63rd (62nd with prepended underscore) character DNS query limit is not surpassed. This option |
| 82 | +requires a string value and defaults to "mongodb". This option MUST only be configurable at the level of a |
| 83 | +`MongoClient`. |
| 84 | + |
| 85 | +#### URI Validation |
| 86 | + |
| 87 | +The driver MUST report an error if either the `srvServiceName` or `srvMaxHosts` URI options are specified with a non-SRV |
| 88 | +URI (i.e. scheme other than `mongodb+srv`). The driver MUST allow specifying the `srvServiceName` and `srvMaxHosts` URI |
| 89 | +options with an SRV URI (i.e. `mongodb+srv` scheme). |
| 90 | + |
| 91 | +If `srvMaxHosts` is a positive integer, the driver MUST throw an error in the following cases: |
| 92 | + |
| 93 | +- The connection string contains a `replicaSet` option. |
| 94 | +- The connection string contains a `loadBalanced` option with a value of `true`. |
| 95 | + |
| 96 | +When validating URI options, the driver MUST first do the SRV and TXT lookup and then perform the validation. For |
| 97 | +drivers that do SRV lookup asynchronously this may result in a `MongoClient` being instantiated but erroring later |
| 98 | +during operation execution. |
| 99 | + |
| 100 | +### Seedlist Discovery |
| 101 | + |
| 102 | +#### Validation Before Querying DNS |
| 103 | + |
| 104 | +It is an error to specify a port in a connection string with the `mongodb+srv` protocol, and the driver MUST raise a |
| 105 | +parse error and MUST NOT do DNS resolution or contact hosts. |
| 106 | + |
| 107 | +It is an error to specify more than one host name in a connection string with the `mongodb+srv` protocol, and the driver |
| 108 | +MUST raise a parse error and MUST NOT do DNS resolution or contact hosts. |
| 109 | + |
| 110 | +If `mongodb+srv` is used, a driver MUST implicitly also enable TLS. Clients can turn this off by passing `tls=false` in |
| 111 | +either the Connection String, or options passed in as parameters in code to the MongoClient constructor (or equivalent |
| 112 | +API for each driver), but not through a TXT record (discussed in a later section). |
| 113 | + |
| 114 | +#### Querying DNS |
| 115 | + |
| 116 | +In this preprocessing step, the driver will query the DNS server for SRV records on the hostname, prefixed with the SRV |
| 117 | +service name and protocol. The SRV service name is provided in the `srvServiceName` URI option and defaults to |
| 118 | +`mongodb`. The protocol is always `tcp`. After prefixing, the URI should look like: `_{srvServiceName}._tcp.{hostname}`. |
| 119 | +This DNS query is expected to respond with one or more SRV records. |
| 120 | + |
| 121 | +The priority and weight fields in returned SRV records MUST be ignored. |
| 122 | + |
| 123 | +If the DNS result returns no SRV records, or no records at all, or a DNS error happens, an error MUST be raised |
| 124 | +indicating that the URI could not be used to find hostnames. The error SHALL include the reason why they could not be |
| 125 | +found. |
| 126 | + |
| 127 | +A driver MUST verify that the host names returned through SRV records share the original SRV's `{domainname}`. In |
| 128 | +addition, SRV records with fewer than three `.` separated parts, the returned hostname MUST have at least one more |
| 129 | +domain level than the SRV record hostname. Drivers MUST raise an error and MUST NOT initiate a connection to any |
| 130 | +returned hostname which does not fulfill these requirements. |
| 131 | + |
| 132 | +The driver MUST NOT attempt to connect to any hosts until the DNS query has returned its results. |
| 133 | + |
| 134 | +If `srvMaxHosts` is zero or greater than or equal to the number of hosts in the DNS result, the driver MUST populate the |
| 135 | +seedlist with all hosts. |
| 136 | + |
| 137 | +If `srvMaxHosts` is greater than zero and less than the number of hosts in the DNS result, the driver MUST randomly |
| 138 | +select that many hosts and use them to populate the seedlist. Drivers SHOULD use the |
| 139 | +[Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm) for |
| 140 | +randomization. |
| 141 | + |
| 142 | +### Default Connection String Options |
| 143 | + |
| 144 | +As a second preprocessing step, a Client MUST also query the DNS server for TXT records on `{hostname}`. If available, a |
| 145 | +TXT record provides default connection string options. The maximum length of a TXT record string is 255 characters, but |
| 146 | +there can be multiple strings per TXT record. A Client MUST support multiple TXT record strings and concatenate them as |
| 147 | +if they were one single string in the order they are defined in each TXT record. The order of multiple character strings |
| 148 | +in each TXT record is guaranteed. A Client MUST NOT allow multiple TXT records for the same host name and MUST raise an |
| 149 | +error when multiple TXT records are encountered. |
| 150 | + |
| 151 | +Information returned within a TXT record is a simple URI string, just like the `{options}` in a connection string. |
| 152 | + |
| 153 | +A Client MUST only support the `authSource`, `replicaSet`, and `loadBalanced` options through a TXT record, and MUST |
| 154 | +raise an error if any other option is encountered. Although using `mongodb+srv://` implicitly enables TLS, a Client MUST |
| 155 | +NOT allow the `ssl` option to be set through a TXT record option. |
| 156 | + |
| 157 | +TXT records MAY be queried either before, in parallel, or after SRV records. Clients MUST query both the SRV and the TXT |
| 158 | +records before attempting any connection to MongoDB. |
| 159 | + |
| 160 | +A Client MUST use options specified in the Connection String, and options passed in as parameters in code to the |
| 161 | +MongoClient constructor (or equivalent API for each driver), to override options provided through TXT records. |
| 162 | + |
| 163 | +If any connection string option in a TXT record is incorrectly formatted, a Client MUST throw a parse exception. |
| 164 | + |
| 165 | +This specification does not change the behaviour of handling unknown keys or incorrect values as is set out in the |
| 166 | +[Connection String spec](../connection-string/connection-string-spec.md#defining-connection-options). Unknown keys or |
| 167 | +incorrect values in default options specified through TXT records MUST be handled in the same way as unknown keys or |
| 168 | +incorrect values directly specified through a Connection String. For example, if a driver that does not support the |
| 169 | +`authSource` option finds `authSource=db` in a TXT record, it MUST handle the unknown option according to the rules in |
| 170 | +the Connection String spec. |
| 171 | + |
| 172 | +### CNAME not supported |
| 173 | + |
| 174 | +The use of DNS CNAME records is not supported. Clients MUST NOT check for a CNAME record on `{hostname}`. A system's DNS |
| 175 | +resolver could transparently handle CNAME, but because of how clients validate records returned from SRV queries, use of |
| 176 | +CNAME could break validation. Seedlist discovery therefore does not recommend or support the use of CNAME records in |
| 177 | +concert with SRV or TXT records. |
| 178 | + |
| 179 | +## Example |
| 180 | + |
| 181 | +If we provide the following URI: |
| 182 | + |
| 183 | +``` |
| 184 | +mongodb+srv://server.mongodb.com/ |
| 185 | +``` |
| 186 | + |
| 187 | +The driver needs to request the DNS server for the SRV record `_mongodb._tcp.server.mongodb.com`. This could return: |
| 188 | + |
| 189 | +``` |
| 190 | +Record TTL Class Priority Weight Port Target |
| 191 | +_mongodb._tcp.server.mongodb.com. 86400 IN SRV 0 5 27317 mongodb1.mongodb.com. |
| 192 | +_mongodb._tcp.server.mongodb.com. 86400 IN SRV 0 5 27017 mongodb2.mongodb.com. |
| 193 | +``` |
| 194 | + |
| 195 | +The returned host names (`mongodb1.mongodb.com` and `mongodb2.mongodb.com`) must share the same domainname |
| 196 | +(`mongodb.com`) as the provided host name (`server.mongodb.com`). |
| 197 | + |
| 198 | +The driver also needs to request the DNS server for the TXT records on `server.mongodb.com`. This could return: |
| 199 | + |
| 200 | +``` |
| 201 | +Record TTL Class Text |
| 202 | +server.mongodb.com. 86400 IN TXT "replicaSet=replProduction&authSource=authDB" |
| 203 | +``` |
| 204 | + |
| 205 | +From the DNS results, the driver now MUST treat the host information as if the following URI was used instead: |
| 206 | + |
| 207 | +``` |
| 208 | +mongodb://mongodb1.mongodb.com:27317,mongodb2.mongodb.com:27107/?ssl=true&replicaSet=replProduction&authSource=authDB |
| 209 | +``` |
| 210 | + |
| 211 | +If we provide the following URI with the same DNS (SRV and TXT) records: |
| 212 | + |
| 213 | +``` |
| 214 | +mongodb+srv://server.mongodb.com/?authSource=otherDB |
| 215 | +``` |
| 216 | + |
| 217 | +Then the default in the TXT record for `authSource` is not used as the value in the connection string overrides it. The |
| 218 | +Client MUST treat the host information as if the following URI was used instead: |
| 219 | + |
| 220 | +``` |
| 221 | +mongodb://mongodb1.mongodb.com:27317,mongodb2.mongodb.com:27107/?ssl=true&replicaSet=replProduction&authSource=otherDB |
| 222 | +``` |
| 223 | + |
| 224 | +## Test Plan |
| 225 | + |
| 226 | +### Prose Tests |
| 227 | + |
| 228 | +See README.md in the accompanying [test directory](tests/README.md). |
| 229 | + |
| 230 | +### Spec Tests |
| 231 | + |
| 232 | +See README.md in the accompanying [test directory](tests/README.md). |
| 233 | + |
| 234 | +Additionally, see the `mongodb+srv` test `invalid-uris.yml` in the |
| 235 | +[Connection String Spec tests](../connection-string/tests/README.md). |
| 236 | + |
| 237 | +## Motivation |
| 238 | + |
| 239 | +Several of our users have asked for this through tickets: |
| 240 | + |
| 241 | +- <https://jira.mongodb.org/browse/DRIVERS-201> |
| 242 | +- <https://jira.mongodb.org/browse/NODE-865> |
| 243 | +- <https://jira.mongodb.org/browse/CSHARP-536> |
| 244 | + |
| 245 | +## Design Rationale |
| 246 | + |
| 247 | +The design specifically calls for a pre-processing stage of the processing of connection URLs to minimize the impact on |
| 248 | +existing functionality. |
| 249 | + |
| 250 | +## Justifications |
| 251 | + |
| 252 | +### Why Are Multiple Key-Value Pairs Allowed in One TXT Record? |
| 253 | + |
| 254 | +One could imagine an alternative design in which each TXT record would allow only one URI option. No `&` character would |
| 255 | +be allowed as a delimiter within TXT records. |
| 256 | + |
| 257 | +In this spec we allow multiple key-value pairs within one TXT record, delimited by `&`, because it will be common for |
| 258 | +all options to fit in a single 255-character TXT record, and it is much more convenient to configure one record in this |
| 259 | +case than to configure several. |
| 260 | + |
| 261 | +Secondly, in some cases the order in which options occur is important. For example, readPreferenceTags can appear both |
| 262 | +multiple times, and the order in which they appear is significant. Because DNS servers may return TXT records in any |
| 263 | +order, it is only possible to guarantee the order in which readPreferenceTags keys appear by having them in the same TXT |
| 264 | +record. |
| 265 | + |
| 266 | +### Why Is There No Mention of UTF-8 Characters? |
| 267 | + |
| 268 | +Although DNS TXT records allow any octet to exist in its value, many DNS providers do not allow non-ASCII characters to |
| 269 | +be configured. As it is unlikely that any option names or values in the connection string have non-ASCII characters, we |
| 270 | +left the behaviour of supporting UTF-8 characters as unspecified. |
| 271 | + |
| 272 | +## Reference Implementation |
| 273 | + |
| 274 | +None yet. |
| 275 | + |
| 276 | +## Backwards Compatibility |
| 277 | + |
| 278 | +There are no backwards compatibility concerns. |
| 279 | + |
| 280 | +## Future Work |
| 281 | + |
| 282 | +In the future we could consider using the priority and weight fields of the SRV records. |
| 283 | + |
| 284 | +## ChangeLog |
| 285 | + |
| 286 | +- 2024-09-24: Removed requirement for URI to have three '.' separated parts; these SRVs have stricter parent domain |
| 287 | + matching requirements for security. Create terminology section. Remove usage of term `{TLD}`. The `{hostname}` now |
| 288 | + refers to the entire hostname, not just the `{subdomain}`. |
| 289 | + |
| 290 | +- 2024-03-06: Migrated from reStructuredText to Markdown. |
| 291 | + |
| 292 | +- 2022-10-05: Revise spec front matter and reformat changelog. |
| 293 | + |
| 294 | +- 2021-10-14: Add `srvMaxHosts` MongoClient option and restructure Seedlist Discovery section. Improve documentation for |
| 295 | + the `srvServiceName` MongoClient option and add a new URI Validation section. |
| 296 | + |
| 297 | +- 2021-09-15: Clarify that service name only defaults to `mongodb`, and should be defined by the `srvServiceName` URI |
| 298 | + option. |
| 299 | + |
| 300 | +- 2021-04-15: Adding in behaviour for load balancer mode. |
| 301 | + |
| 302 | +- 2019-03-07: Clarify that CNAME is not supported |
| 303 | + |
| 304 | +- 2018-02-08: Clarify that `{options}}` in the [Specification](#specification) section includes all the optional |
| 305 | + elements from the Connection String specification. |
| 306 | + |
| 307 | +- 2017-11-21: Add clause that using `mongodb+srv://` implies enabling TLS. Add restriction that only `authSource` and |
| 308 | + `replicaSet` are allows in TXT records. Add restriction that only one TXT record is supported share the same parent |
| 309 | + domain name as the given host name. |
| 310 | + |
| 311 | +- 2017-11-17: Add new rule that indicates that host names in returned SRV records MUST share the same parent domain name |
| 312 | + as the given host name. Remove language and tests for non-ASCII characters. |
| 313 | + |
| 314 | +- 2017-11-07: Clarified that all parts of listable options such as readPreferenceTags are ignored if they are also |
| 315 | + present in options to the MongoClient constructor. Clarified which host names to use for SRV and TXT DNS queries. |
| 316 | + |
| 317 | +- 2017-11-01: Clarified that individual TXT records can have multiple strings. |
| 318 | + |
| 319 | +- 2017-10-31: Added a clause that specifying two host names with a `mongodb+srv://` URI is not allowed. Added a few more |
| 320 | + test cases. |
| 321 | + |
| 322 | +- 2017-10-18: Removed prohibition of raising DNS related errors when parsing the URI. |
| 323 | + |
| 324 | +- 2017-10-04: Removed from [Future Work](#future-work) the line about multiple MongoS discovery. The current |
| 325 | + specification already allows for it, as multiple host names which are all MongoS servers is already allowed under |
| 326 | + SDAM. And this specification does not modify SDAM. Added support for connection string options through TXT records. |
| 327 | + |
| 328 | +- 2017-09-19: Clarify that host names in `mongodb+srv://` URLs work like normal host specifications. |
| 329 | + |
| 330 | +- 2017-09-01: Updated test plan with YAML tests, and moved prose tests for URI parsing into invalid-uris.yml in the |
| 331 | + Connection String Spec tests. |
0 commit comments