Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(NODE-6289): allow valid srv hostnames with less than 3 parts #4197

Open
wants to merge 21 commits into
base: main
Choose a base branch
from

Conversation

aditi-khare-mongoDB
Copy link
Contributor

@aditi-khare-mongoDB aditi-khare-mongoDB commented Aug 15, 2024

Description

Downstream changes for DRIVERS-2922 (PR).

What is changing?

  • Remove logic asserting that SRV URIs need 3 parts
  • When we check if a returned address matches its parent SRV, an SRV with <3 parts must assert that the returned address contains an additional domain level
  • Add in prose tests.
Is there new documentation needed for these changes?

No

What is the motivation for this change?

Do not throw an error on valid URI formats pre-DNS resolution, and require stricter domain matching post-DNS resolution.

Release Highlight

Allow SRV hostnames with less than three . separated parts

The client now accepts SRV hostname strings with one or two . separated parts.

For example, the following code no longer throws an error.

await new MongoClient('mongodb+srv://localhost').connect();

For security reasons, the returned addresses of SRV strings with less than three parts must end with the entire SRV hostname and contain at least one additional domain level. This is because this added validation ensures that the returned address(es) are from a known host. In future releases, we plan on extending this validation to SRV strings with three or more parts, as well.

// Example 1: Validation fails since the returned address doesn't end with the entire SRV hostname
'mongodb+srv://mySite.com' => 'myEvilSite.com' 

// Example 2: Validation fails since the returned address is identical to the SRV hostname
'mongodb+srv://mySite.com' => 'mySite.com' 

// Example 3: Validation passes since the returned address ends with the entire SRV hostname and contains an additional domain level
'mongodb+srv://mySite.com' => 'cluster_1.mySite.com' 

Double check the following

  • Ran npm run check:lint script
  • Self-review completed using the steps outlined here
  • PR title follows the correct format: type(NODE-xxxx)[!]: description
    • Example: feat(NODE-1234)!: rewriting everything in coffeescript
  • Changes are covered by tests
  • New TODOs have a related JIRA ticket

@aditi-khare-mongoDB aditi-khare-mongoDB changed the title feat(NODE-6289): DRIVERS-2922 Downstream Changes PoC feat(NODE-6289): DRIVERS 2922 Downstream Changes PoC Aug 15, 2024
@aditi-khare-mongoDB aditi-khare-mongoDB changed the title feat(NODE-6289): DRIVERS 2922 Downstream Changes PoC feat(NODE-6289): Allow valid SRV hostnames with less than 3 parts Sep 5, 2024
@aditi-khare-mongoDB aditi-khare-mongoDB changed the title feat(NODE-6289): Allow valid SRV hostnames with less than 3 parts feat(NODE-6289): allow valid srv hostnames with less than 3 parts Sep 5, 2024
@aditi-khare-mongoDB aditi-khare-mongoDB marked this pull request as ready for review September 19, 2024 15:45
@W-A-James W-A-James self-assigned this Sep 19, 2024
@W-A-James W-A-James self-requested a review September 19, 2024 15:47
@W-A-James W-A-James added the Primary Review In Review with primary reviewer, not yet ready for team's eyes label Sep 19, 2024
W-A-James
W-A-James previously approved these changes Sep 27, 2024
@W-A-James W-A-James added Team Review Needs review from team and removed Primary Review In Review with primary reviewer, not yet ready for team's eyes labels Sep 27, 2024
@dariakp
Copy link
Contributor

dariakp commented Sep 30, 2024

@aditi-khare-mongoDB @W-A-James Can we confirm the failing tests are all accounted for?

@aditi-khare-mongoDB
Copy link
Contributor Author

@dariakp Seems like the two red failing tests are flaky. I doubt the purple failures would contain any failures if they weren't system failures. For example, 5.0-node-latest-server fails but not 4.0-node-latest or 6.0-node-latest, which makes me assume 5.0-node-latest would pass if not for the CI issues.

@@ -127,8 +127,11 @@ export class SrvPoller extends TypedEventEmitter<SrvPollerEvents> {

const finalAddresses: dns.SrvRecord[] = [];
for (const record of srvRecords) {
if (matchesParentDomain(record.name, this.srvHost)) {
try {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find a kickoff document for this work, so I am not sure if this is something that has already been discussed, but how frequently is this function invoked? Is it in the hot path for anything? This construction, while cleaner, is less performant (since try catch is more expensive than a simple if/then, and the additional function call for the no-op may or may not get optimized).

src/utils.ts Outdated
normalizedAddress.split('.').length <= normalizedSrvHost.split('.').length
) {
// TODO(NODE-3484): Replace with MongoConnectionStringError
throw new MongoAPIError('Server record does not have least one more domain than parent URI');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the grammar on this needs some adjustment - could you double check the wording? I think it was probably meant to be Server record does not have at least one more domain level than parent URI

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch!

src/utils.ts Outdated
throw new MongoAPIError('Server record does not have least one more domain than parent URI');
}
if (!addressDomain.endsWith(srvHostDomain)) {
// TODO(NODE-3484): Replace with MongoConnectionStringError
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NODE-3484 is about MongoParseError specifically, is that the right ticket for this work and do we definitely want a more specific error here? Even if so, I am not sure that we'd want to call it "MongoConnectionString", since, if I understand correcty. we are testing resolved records and not something that is specified in the connection string itself.

Copy link
Contributor Author

@aditi-khare-mongoDB aditi-khare-mongoDB Oct 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed the TODO, it's a remanent from when this function was first implemented, and the ticket has sat in the backlog for years at this point. More importantly, it wouldn't be a connection string error technically, more of a 'SRV resolution returns invalid values' error, so i think MongoAPIError is sufficient here.

import { topologyWithPlaceholderClient } from '../../tools/utils';

describe('Initial DNS Seedlist Discovery (Prose Tests)', () => {
context('1. When running validation on an SRV string before DNS resolution', function () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For easy audit purposes (e.g. in evg), we should match the number and title of the prose test in the context block and capture the full instructions text in comments.

@@ -939,7 +939,7 @@ describe('driver utils', function () {
});
});

describe('matchesParentDomain()', () => {
describe('checkParentDomainMatch()', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we add analogous tests for what happens when we have a trailing dot on a 2- or 1- part srv?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea! Just added them in

src/utils.ts Outdated
// Remove trailing dot if exists on either the resolved address or the srv hostname
const normalizedAddress = address.endsWith('.') ? address.slice(0, address.length - 1) : address;
const normalizedSrvHost = srvHost.endsWith('.') ? srvHost.slice(0, srvHost.length - 1) : srvHost;

const allCharacterBeforeFirstDot = /^.*?\./;
const srvIsLessThanThreeParts = srvHost.split('.').length < 3;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the correct check? I would think we are interested in checking whether the normalized host has fewer than 3 parts, since I don't think we want to consider the trailing dot on a 2- part host any differently, if I understand correctly. If you agree, could you make sure that there are new tests in the unit test section that fail with the code as it currently is and pass when the code is updated to check the normalized part count instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, you're right, I've added in a new test that would have failed otherwise (the 'extra domain level' one) and fixed a typo in these section.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Team Review Needs review from team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants