Skip to content

dns: validate both addresses before applying them in setLocalAddress - #67060

Open
Marti2203 wants to merge 1 commit into
nodejs:mainfrom
Marti2203:dns-setlocaladdress-validate-first
Open

Marti2203 wants to merge 1 commit into
nodejs:mainfrom
Marti2203:dns-setlocaladdress-validate-first

Conversation

@Marti2203

Copy link
Copy Markdown

Resolver#setLocalAddress() applied the first address to the c-ares channel before it parsed
and validated the second one. A call that then threw ERR_INVALID_ARG_VALUE (two addresses of
the same family, or an invalid second address) left the first address applied, so later queries
went out from an address the caller had been told was rejected.

This change parses and validates both arguments first and only then calls
ares_set_local_ip4() / ares_set_local_ip6(). In plain terms, SetLocalAddress() now
decides whether the whole call is valid before it touches the channel, so a call that throws
changes nothing. The behaviour for valid calls is unchanged: the two setters are called in the
same order as before, and with a single argument the other family is still reset to "any".

The new test, test/parallel/test-dns-setlocaladdress-rejected.js, runs a local UDP server
on 127.0.0.1 and records the source address of the DNS query. It calls
setLocalAddress('127.0.0.2'), then two calls that throw ('127.0.0.3', '127.0.0.4' and
'127.0.0.5', 'bad'), and checks that the query still comes from 127.0.0.2. It needs no
network access. It is skipped on non-Linux platforms, where only 127.0.0.1 is bound to the
loopback interface by default.

Fixes: #67049

This bug was found by an LLM-assisted static analysis tool; the fix and test were drafted with
the help of a coding agent. I reproduced the bug and verified the fix on Linux (the test fails
before the change and passes after it), and ran the existing dns tests.

SetLocalAddress() applied the first address to the c-ares channel with
ares_set_local_ip4()/ares_set_local_ip6() before parsing and validating
the second one. A call that then threw ERR_INVALID_ARG_VALUE, because
both addresses were of the same family or the second address was
invalid, left the first address in effect, so later queries were sent
from an address the caller had been told was rejected.

Parse and validate both arguments first and only then apply them. With
a single argument the other family is still reset to "any", as before.

Fixes: nodejs#67049
Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/net

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. cares Issues and PRs related to the c-ares dependency or the cares_wrap binding. needs-ci PRs that need a full CI run. labels Oct 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Welcome to Node.js, and thank you for your first contribution!

Before review, please take a moment to read:

Please make sure every commit is signed off. For a first pull request, GitHub Actions require collaborator approval and Jenkins CI must be started by a collaborator or triager, so an initial wait is normal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. cares Issues and PRs related to the c-ares dependency or the cares_wrap binding. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dns: Resolver#setLocalAddress() applies the first address even when it throws

2 participants