-
Notifications
You must be signed in to change notification settings - Fork 541
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
Feature request: allow a custom dns lookup function to be supplied #421
Comments
Sure, would you like to send a PR? |
Would this be the correct change? Make these Line 871 in 2b56a54
Are these other places that would need to be updated also? |
I think this could be resolved through #852 |
I’m running into this issue as well. My use case is an app that needs to connect to a server that can be accessed over the public internet but not within the virtual network where my app is running. In an older app with the same need, I wrote this code to patch DNS resolution for requests to use a public DNS server as a fallback when the internal lookup failed: import { lookup } from 'node:dns'
import http from 'node:http'
import https from 'node:https'
export async function patchDnsResolution() {
http.globalAgent = new http.Agent({
keepAlive: true,
lookup: customLookup,
})
https.globalAgent = new https.Agent({
keepAlive: true,
lookup: customLookup,
})
}
function customLookup(hostname, _family, callback) {
lookup(hostname, 4, (lookupError, address, family) => {
if (hostname === 'localhost') {
return callback(undefined, '127.0.0.1', 4)
}
if (lookupError) {
console.log(`Using public DNS resolver to look up ${hostname}`)
// https://developers.cloudflare.com/1.1.1.1/encrypted-dns/dns-over-https/make-api-requests
fetchWithTimeout(`https://1.1.1.1/dns-query?name=${encodeURIComponent(hostname)}`, {
headers: {
accept: 'application/dns-json',
},
})
.then(response => response.json())
.then(response => {
if (response?.Answer) {
// https://developers.cloudflare.com/1.1.1.1/encrypted-dns/dns-over-https/make-api-requests/dns-json
// Find the first IPv4 or IPv6 address; https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4
const { data: address, type } = response.Answer.find(({ type }) => type === 1 || type === 28)
family = type === 1 ? 4 : 6 // IPv4 type is 1, IPv6 type is 28
callback(undefined, address, family)
} else {
callback(new Error(`Public DNS resolver unrecognized response: ${response}`))
}
}).catch(error => {
console.error(`Public DNS resolver error: ${error}`)
})
} else {
callback(undefined, address, family)
}
})
}
async function fetchWithTimeout(resource, options = {timeout: 2000}) {
const { timeout } = options
const controller = new AbortController()
const id = setTimeout(() => controller.abort(), timeout)
const response = await fetch(resource, {
...options,
signal: controller.signal
})
clearTimeout(id)
return response
} In my new app, one of its dependencies uses Node’s global |
@ronag @GeoffreyBooth shouldn't this be solved by using the |
The connect option solves this. |
Can you provide a working example? |
I think I've got it working by using an Agent-instance with the connect-option. I don't know whether this is the preferred option, but it seems to work: import { Agent } from 'undici';
await fetch('https://example.com', {
dispatcher: new Agent({
connect: {
lookup: (hostname, options, callback) => {
return dns.lookup(hostname, options, callback);
},
},
}),
}); Alternatively, the Agent can be registered globally using the |
The
http
built-in module can have a customlookup
function defined, which is great as it enables applications to decide if they want to implement a dns-caching system or something else.Do we think it is a good idea to also implement such a feature for undici?
The text was updated successfully, but these errors were encountered: