diff --git a/source/initial-dns-seedlist-discovery/initial-dns-seedlist-discovery.md b/source/initial-dns-seedlist-discovery/initial-dns-seedlist-discovery.md index a56ee6fb33..0c01577ca9 100644 --- a/source/initial-dns-seedlist-discovery/initial-dns-seedlist-discovery.md +++ b/source/initial-dns-seedlist-discovery/initial-dns-seedlist-discovery.md @@ -9,9 +9,9 @@ ______________________________________________________________________ Presently, seeding a driver with an initial list of ReplicaSet or MongoS addresses is somewhat cumbersome, requiring a comma-delimited list of host names to attempt connections to. A standardized answer to this problem exists in the form -of SRV records, which allow administrators to configure a single domain to return a list of host names. Supporting this -feature would assist our users by decreasing maintenance load, primarily by removing the need to maintain seed lists at -an application level. +of SRV records, which allow administrators to configure a single SRV record to return a list of host names. Supporting +this feature would assist our users by decreasing maintenance load, primarily by removing the need to maintain seed +lists at an application level. This specification builds on the [Connection String](../connection-string/connection-string-spec.md) specification. It adds a new protocol scheme and modifies how the @@ -31,12 +31,38 @@ step before it considers the connection string and SDAM specifications. In this host names is replaced with a single host name. The format is: ``` -mongodb+srv://{hostname}.{domainname}/{options} +mongodb+srv://{hostname}/{options} ``` `{options}` refers to the optional elements from the [Connection String](../connection-string/connection-string-spec.md) specification following the `Host Information`. This includes the `Auth database` and `Connection Options`. +For the purposes of this document, `{hostname}` will be divided using the following terminology. If an SRV `{hostname}` +has: + +1. Three or more `.` separated parts, then the left-most part is the `{subdomain}` and the remaining portion is the + `{domainname}`. + + - Examples: + - `{hostname}` = `cluster_1.tests.mongodb.co.uk` + + - `{subdomain}` = `cluster_1` + - `{domainname}` = `tests.mongodb.co.uk` + + - `{hostname}` = `hosts_34.example.com` + + - `{subdomain}` = `hosts_34` + - `{domainname}` = `example.com` + +2. One or two `.` separated part(s), then the `{hostname}` is equivalent to the `{domainname}`, and there is no + subdomain. + + - Examples: + - `{hostname}` = `{domainname}` = `localhost` + - `{hostname}` = `{domainname}` = `mongodb.local` + +Only `{domainname}` is used during SRV record verification and `{subdomain}` is ignored. + ### MongoClient Configuration #### srvMaxHosts @@ -81,20 +107,16 @@ parse error and MUST NOT do DNS resolution or contact hosts. It is an error to specify more than one host name in a connection string with the `mongodb+srv` protocol, and the driver MUST raise a parse error and MUST NOT do DNS resolution or contact hosts. -A driver MUST verify that in addition to the `{hostname}`, the `{domainname}` consists of at least two parts: the domain -name, and a TLD. Drivers MUST raise an error and MUST NOT contact the DNS server to obtain SRV (or TXT records) if the -full URI does not consist of at least three parts. - If `mongodb+srv` is used, a driver MUST implicitly also enable TLS. Clients can turn this off by passing `tls=false` in either the Connection String, or options passed in as parameters in code to the MongoClient constructor (or equivalent API for each driver), but not through a TXT record (discussed in a later section). #### Querying DNS -In this preprocessing step, the driver will query the DNS server for SRV records on `{hostname}.{domainname}`, prefixed -with the SRV service name and protocol. The SRV service name is provided in the `srvServiceName` URI option and defaults -to `mongodb`. The protocol is always `tcp`. After prefixing, the URI should look like: -`_{srvServiceName}._tcp.{hostname}.{domainname}`. This DNS query is expected to respond with one or more SRV records. +In this preprocessing step, the driver will query the DNS server for SRV records on the hostname, prefixed with the SRV +service name and protocol. The SRV service name is provided in the `srvServiceName` URI option and defaults to +`mongodb`. The protocol is always `tcp`. After prefixing, the URI should look like: `_{srvServiceName}._tcp.{hostname}`. +This DNS query is expected to respond with one or more SRV records. The priority and weight fields in returned SRV records MUST be ignored. @@ -102,9 +124,10 @@ If the DNS result returns no SRV records, or no records at all, or a DNS error h indicating that the URI could not be used to find hostnames. The error SHALL include the reason why they could not be found. -A driver MUST verify that the host names returned through SRV records have the same parent `{domainname}`. Drivers MUST -raise an error and MUST NOT initiate a connection to any returned host name which does not share the same -`{domainname}`. +A driver MUST verify that the host names returned through SRV records share the original SRV's `{domainname}`. In +addition, SRV records with fewer than three `.` separated parts, the returned hostname MUST have at least one more +domain level than the SRV record hostname. Drivers MUST raise an error and MUST NOT initiate a connection to any +returned hostname which does not fulfill these requirements. The driver MUST NOT attempt to connect to any hosts until the DNS query has returned its results. @@ -118,12 +141,12 @@ randomization. ### Default Connection String Options -As a second preprocessing step, a Client MUST also query the DNS server for TXT records on `{hostname}.{domainname}`. If -available, a TXT record provides default connection string options. The maximum length of a TXT record string is 255 -characters, but there can be multiple strings per TXT record. A Client MUST support multiple TXT record strings and -concatenate them as if they were one single string in the order they are defined in each TXT record. The order of -multiple character strings in each TXT record is guaranteed. A Client MUST NOT allow multiple TXT records for the same -host name and MUST raise an error when multiple TXT records are encountered. +As a second preprocessing step, a Client MUST also query the DNS server for TXT records on `{hostname}`. If available, a +TXT record provides default connection string options. The maximum length of a TXT record string is 255 characters, but +there can be multiple strings per TXT record. A Client MUST support multiple TXT record strings and concatenate them as +if they were one single string in the order they are defined in each TXT record. The order of multiple character strings +in each TXT record is guaranteed. A Client MUST NOT allow multiple TXT records for the same host name and MUST raise an +error when multiple TXT records are encountered. Information returned within a TXT record is a simple URI string, just like the `{options}` in a connection string. @@ -148,10 +171,10 @@ the Connection String spec. ### CNAME not supported -The use of DNS CNAME records is not supported. Clients MUST NOT check for a CNAME record on `{hostname}.{domainname}`. A -system's DNS resolver could transparently handle CNAME, but because of how clients validate records returned from SRV -queries, use of CNAME could break validation. Seedlist discovery therefore does not recommend or support the use of -CNAME records in concert with SRV or TXT records. +The use of DNS CNAME records is not supported. Clients MUST NOT check for a CNAME record on `{hostname}`. A system's DNS +resolver could transparently handle CNAME, but because of how clients validate records returned from SRV queries, use of +CNAME could break validation. Seedlist discovery therefore does not recommend or support the use of CNAME records in +concert with SRV or TXT records. ## Example @@ -169,7 +192,7 @@ _mongodb._tcp.server.mongodb.com. 86400 IN SRV 0 5 27317 mongodb1. _mongodb._tcp.server.mongodb.com. 86400 IN SRV 0 5 27017 mongodb2.mongodb.com. ``` -The returned host names (`mongodb1.mongodb.com` and `mongodb2.mongodb.com`) must share the same parent domain name +The returned host names (`mongodb1.mongodb.com` and `mongodb2.mongodb.com`) must share the same domainname (`mongodb.com`) as the provided host name (`server.mongodb.com`). The driver also needs to request the DNS server for the TXT records on `server.mongodb.com`. This could return: @@ -200,6 +223,12 @@ mongodb://mongodb1.mongodb.com:27317,mongodb2.mongodb.com:27107/?ssl=true&replic ## Test Plan +### Prose Tests + +See README.md in the accompanying [test directory](tests/README.md). + +### Spec Tests + See README.md in the accompanying [test directory](tests/README.md). Additionally, see the `mongodb+srv` test `invalid-uris.yml` in the @@ -254,6 +283,10 @@ In the future we could consider using the priority and weight fields of the SRV ## ChangeLog +- 2024-09-24: Removed requirement for URI to have three '.' separated parts; these SRVs have stricter parent domain + matching requirements for security. Create terminology section. Remove usage of term `{TLD}`. The `{hostname}` now + refers to the entire hostname, not just the `{subdomain}`. + - 2024-03-06: Migrated from reStructuredText to Markdown. - 2022-10-05: Revise spec front matter and reformat changelog. diff --git a/source/initial-dns-seedlist-discovery/tests/README.md b/source/initial-dns-seedlist-discovery/tests/README.md index 50a77cb3f8..99a1e8e3f0 100644 --- a/source/initial-dns-seedlist-discovery/tests/README.md +++ b/source/initial-dns-seedlist-discovery/tests/README.md @@ -3,6 +3,51 @@ This directory contains platform-independent tests that drivers can use to prove their conformance to the Initial DNS Seedlist Discovery spec. +## Prose Tests + +For the following prose tests, it is assumed drivers are be able to stub DNS results to easily test invalid DNS +resolution results. + +### 1. Allow SRVs with fewer than 3 `.` separated parts + +When running validation on an SRV string before DNS resolution, do not throw a error due to number of SRV parts. + +- `mongodb+srv://localhost` +- `mongodb+srv://mongo.local` + +### 2. Throw when return address does not end with SRV domain + +When given a returned address that does NOT end with the original SRV's domain name, throw a runtime error. + +For this test, run each of the following cases: + +- the SRV `mongodb+srv://localhost` resolving to `localhost.mongodb` +- the SRV `mongodb+srv://mongo.local` resolving to `test_1.evil.local` +- the SRV `mongodb+srv://blogs.mongodb.com` resolving to `blogs.evil.com` + +Remember, the domain of an SRV with one or two `.` separated parts is the SRVs entire hostname. + +### 3. Throw when return address is identical to SRV hostname + +When given a returned address that is identical to the SRV hostname and the SRV hostname has fewer than three `.` +separated parts, throw a runtime error. + +For this test, run each of the following cases: + +- the SRV `mongodb+srv://localhost` resolving to `localhost` +- the SRV `mongodb+srv://mongo.local` resolving to `mongo.local` + +### 4. Throw when return address does not contain `.` separating shared part of domain + +When given a returned address that does NOT share the domain name of the SRV record because it's missing a `.`, throw a +runtime error. + +For this test, run each of the following cases: + +- the SRV `mongodb+srv://localhost` resolving to `test_1.cluster_1localhost` +- the SRV `mongodb+srv://mongo.local` resolving to `test_1.my_hostmongo.local` +- the SRV `mongodb+srv://blogs.mongodb.com` resolving to `cluster.testmongodb.com` + ## Test Setup The tests in the `replica-set` directory MUST be executed against a three-node replica set on localhost ports 27017,