Skip to content

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

Open

Description

@Marti2203

Version

v24.22.1 (same code on main at 3983092)

Platform

Linux 5.15.0-139-generic x86_64 (Debian 12 container)

Subsystem

dns

What steps will reproduce the bug?

'use strict';
const dgram = require('node:dgram');
const { Resolver } = require('node:dns');
const server = dgram.createSocket('udp4');
server.on('message', (msg, rinfo) => {
  console.log('query from', rinfo.address);
  server.close();
});
server.bind(0, '127.0.0.1', () => {
  const r = new Resolver({ timeout: 200, tries: 1 });
  r.setServers([`127.0.0.1:${server.address().port}`]);
  r.setLocalAddress('127.0.0.2');
  try {
    r.setLocalAddress('127.0.0.3', '127.0.0.4');
  } catch (e) {
    console.log(e.code, e.message);
  }
  r.resolve4('example.test', () => {});
});

How often does it reproduce? Is there a required condition?

Always. It happens whenever the second argument is rejected (two addresses of the same family,
or an invalid second address).

What is the expected behavior? Why is that the expected behavior?

A call that throws ERR_INVALID_ARG_VALUE should leave the resolver unchanged, so queries keep
going out from 127.0.0.2.

What do you see instead?

ERR_INVALID_ARG_VALUE Cannot specify two IPv4 addresses.
query from 127.0.0.3

The first address from the rejected call is already in effect.

Additional information

SetLocalAddress in src/cares_wrap.cc calls ares_set_local_ip4() / ares_set_local_ip6() for the first address before it parses and validates the second one, so every return after a rejected second argument leaves the first address applied. A possible fix is to parse and validate both arguments first (including the same-family check) and only then call ares_set_local_ip4() / ares_set_local_ip6(). I'm happy to open a PR along those lines if that approach sounds right.

This issue was found by an LLM-Enhanced Static Analysis Engine and verified manually.

Activity

  1. nikolas-sapa commented on Oct 27, 2026

    @nikolas-sapa

    Reproduced on macOS and Linux (Node v26.11.1 and v24.22.1).

    The proposed approach of validating both arguments and enforcing the same-family check before invoking ares_set_local_ip4/ares_set_local_ip6 makes complete sense. Validating upfront preserves strong exception safety so a thrown ERR_INVALID_ARG_VALUE leaves the resolver instance in its previous configuration. Looking forward to your PR!

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions