Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Custom DNS resolver for any request in NodeJS

Tags:

node.js

dns

I'm looking to find a way to use a custom DNS resolver for a nodejs request using node-fetch. I think there is a star of explaining here : Node override request IP resolution but I can't manage to make it work for any request. My goal is to use an alternative DNS resolver, such as cloudflare (1.1.1.1) or Google public DNS (8.8.8.8) instead the OS / ISP default DNS resolution.

import http from "http";
import https from "https";
import fetch from "node-fetch";

const staticLookup = (ip: string, v?: number) => (hostname: string, _: null, cb: Function) => {
  cb(null, ip, v || 4);
};

const staticDnsAgent = (scheme: "http" | "https", ip: string) => {
  const httpModule = scheme === "http" ? http : https;
  return new httpModule.Agent({ lookup: staticLookup(ip), rejectUnauthorized: false });
};

// Both request are not working
fetch(`https://api.github.com/search/issues?q=Hello%20World`, {
  agent: staticDnsAgent("https", "1.1.1.1")
})

fetch(`http://jsonplaceholder.typicode.com/todos`, {
  agent: staticDnsAgent("http", "8.8.8.8")
})

I'm struggling a bit to find a way to make this example work, I'm pretty sure I have to use the nodejs DNS module and set a custom server.

like image 793
Some one Avatar asked Mar 27 '26 03:03

Some one


2 Answers

Thanks to Martheen who answered in my first post I was able to achieve the result here :

import http from "http";
import https from "https";
import dns from "dns/promises";
import fetch from "node-fetch";

// Cloud flare dns
dns.setServers([
  "1.1.1.1",
  "[2606:4700:4700::1111]",
]);

const staticLookup = () => async (hostname: string, _: null, cb: Function) => {
  const ips = await dns.resolve(hostname);

  if (ips.length === 0) {
    throw new Error(`Unable to resolve ${hostname}`);
  }

  cb(null, ips[0], 4);
};

const staticDnsAgent = (scheme: "http" | "https") => {
  const httpModule = scheme === "http" ? http : https;
  return new httpModule.Agent({ lookup: staticLookup() });
};

fetch(`https://api.github.com/search/issues?q=Hello%20World`, {
  agent: staticDnsAgent("https")
})

fetch(`http://jsonplaceholder.typicode.com/todos`, {
  agent: staticDnsAgent("http")
})

like image 50
Some one Avatar answered Mar 28 '26 18:03

Some one


If you tried the accepted answer's solution, and you get an error saying something like "Invalid IP address: undefined", make sure to check the second argument's all property (_.all). If it is true, you must pass the IPs + family in array form like this (cb(null, [{ address: ip, family: 4 }])). Else, you can pass the IP as per accepted answer.

Source: https://nodejs.org/api/dns.html#dnslookuphostname-options-callback, where it says

With the all option set to true, the arguments for callback change to (err, addresses)

Couldn't comment to the accepted answer, so had to say this as an answer.

like image 35
vocafeuvre Avatar answered Mar 28 '26 16:03

vocafeuvre