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.
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")
})
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With