Skip to content

Commit

Permalink
DRIVERS-2922: Allow valid SRV hostnames with fewer than 3 parts (#1628)
Browse files Browse the repository at this point in the history
* feat(DRIVERS-2922): loosen options parser restrictions

lint

clarify

fix capitalization

* add test criteria

* grammar fix

* wording fix

* temp commit - changing terminology

* change terminology

* update changelog

* add in prose test ref

* add parent matching requirements

* update changelod

* added in new prose test requirements + fixed formatting

* requested changes

* requested changes 2

* uniform formatting + fix typo

* team review requested changes

* team review requested changes

* team review requested changes 2

* update deprecation comment

* typo

* clarify subdomain

* add in Shanes test

* update changelog date

* add in specific cases

* fix test cases

* fix tests

* fix tests

* grammar fix
  • Loading branch information
aditi-khare-mongoDB authored Sep 24, 2024
1 parent 30251e8 commit 8e9d768
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -81,30 +107,27 @@ 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.

If the DNS result returns no SRV records, or no records at all, or a DNS error happens, an error MUST be raised
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.

Expand All @@ -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.

Expand All @@ -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

Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
45 changes: 45 additions & 0 deletions source/initial-dns-seedlist-discovery/tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 8e9d768

Please sign in to comment.