Skip to content

Instantly share code, notes, and snippets.

@serious-angel
Last active January 31, 2026 02:48
Show Gist options
  • Select an option

  • Save serious-angel/f6c25f177c840a6e36ac08bf0d3c2d85 to your computer and use it in GitHub Desktop.

Select an option

Save serious-angel/f6c25f177c840a6e36ac08bf0d3c2d85 to your computer and use it in GitHub Desktop.
DNS Latency Node v21+ script example
// ...
[2026-01-31T02:35:27.109Z] [ 9/10] [
  {
    host: 'python.org',
    latency: 5,
    resolved: [
      { address: '151.101.64.223', ttl: 214, type: 'A' },
      { address: '151.101.0.223', ttl: 214, type: 'A' },
      { address: '151.101.128.223', ttl: 214, type: 'A' },
      { address: '151.101.192.223', ttl: 214, type: 'A' },
      { address: '2a04:4e42:600::223', ttl: 214, type: 'AAAA' },
      { address: '2a04:4e42:400::223', ttl: 214, type: 'AAAA' },
      { address: '2a04:4e42:200::223', ttl: 214, type: 'AAAA' },
      { address: '2a04:4e42::223', ttl: 214, type: 'AAAA' },
      { value: 'ns-2046.awsdns-63.co.uk', type: 'NS' },
      { value: 'ns-981.awsdns-58.net', type: 'NS' },
      { value: 'ns-484.awsdns-60.com', type: 'NS' },
      { value: 'ns-1134.awsdns-13.org', type: 'NS' },
      { entries: [ '888acb5757da46ad83b7e341ec544c64' ], type: 'TXT' },
      { entries: [ 'libera-1298aas' ], type: 'TXT' },
      { entries: [ 'google-site-verification=9852CbTRhQ51-9gCUayPbGYqJeBle_MXLb6E4AL_qQk' ], type: 'TXT' },
      { entries: [ 'google-site-verification=w3b8mU3wU6cZ8uSrj3E_5f1frPejJskDpSp_nMWJ99o' ], type: 'TXT' },
      { entries: [ 'google-site-verification=QALZObrGl2OVG8lWUE40uVSMCAka316yADn9ZfCU5OA' ], type: 'TXT' },
      { entries: [ 'google-site-verification=dqhMiMzpbkSyEhgjGKyEOMlEg2tF0MSHD7UN-MYfD-M' ], type: 'TXT' },
      { entries: [ '_globalsign-domain-verification=B57sRQpmte4G4w-gavZbVNmmNsMxGp5kcL19UP2599' ], type: 'TXT' },
      { entries: [ 'status-page-domain-verification=9y2klhzbxsgk' ], type: 'TXT' },
      { entries: [ 'MS=73147F1EC0843C399CF17F586EC6B8EAF8C57961' ], type: 'TXT' },
      { entries: [ 'v=spf1 mx ip4:188.166.95.178/32 ip6:2a03:b0c0:2:d0::71:1 include:stspg-customer.com include:_spf.google.com include:mailgun.org ~all' ], type: 'TXT' },
      { entries: [ 'twilio-domain-verification=1c295667813cc0aaae819ed7657818f8' ], type: 'TXT' },
      { nsname: 'ns-2046.awsdns-63.co.uk', hostmaster: 'awsdns-hostmaster.amazon.com', serial: 1, refresh: 7200, retry: 900, expire: 1209600, minttl: 86400, type: 'SOA' }
    ]
  },
  { host: 'mail.python.org', latency: 0, resolved: [ { address: '188.166.95.178', ttl: 86190, type: 'A' }, { address: '2a03:b0c0:2:d0::71:1', ttl: 86190, type: 'AAAA' } ] },
  { host: 'front.python.org', latency: 1, resolved: [ { address: '140.211.10.69', ttl: 86331, type: 'A' } ] }
]
┌──────────────────┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ (index)          │ 0123456789 │
├──────────────────┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
│ python.org3398765775 │
│ mail.python.org1901153190 │
│ front.python.org1161111351 │
└──────────────────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
┌──────────────────┬───────────────────┬───────────────────┬───────────────────┬───────────────────┬──────────────────┬──────────────────┬──────────────────┬───────────────────┬───────────────────┬──────────────────┐
│ (index)          │ 0123456789                │
├──────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼──────────────────┼──────────────────┼──────────────────┼───────────────────┼───────────────────┼──────────────────┤
│ python.org       │ '151.101.192.223' │ '151.101.192.223' │ '151.101.128.223' │ '151.101.128.223' │ '151.101.0.223'  │ '151.101.64.223' │ '151.101.0.223'  │ '151.101.128.223' │ '151.101.192.223' │ '151.101.64.223' │
│ mail.python.org  │ '188.166.95.178'  │ '188.166.95.178'  │ '188.166.95.178'  │ '188.166.95.178'  │ '188.166.95.178' │ '188.166.95.178' │ '188.166.95.178' │ '188.166.95.178'  │ '188.166.95.178'  │ '188.166.95.178' │
│ front.python.org │ '140.211.10.69'   │ '140.211.10.69'   │ '140.211.10.69'   │ '140.211.10.69'   │ '140.211.10.69'  │ '140.211.10.69'  │ '140.211.10.69'  │ '140.211.10.69'   │ '140.211.10.69'   │ '140.211.10.69'  │
└──────────────────┴───────────────────┴───────────────────┴───────────────────┴───────────────────┴──────────────────┴──────────────────┴──────────────────┴───────────────────┴───────────────────┴──────────────────┘
# 1. Monitor DNS resolution activity.
sudo resolvectl monitor 2>&1 \
| grep -P --line-buffered -- '(A: .*python.* A .+|Q: .*python.* A)$' \
| TZ= ts '[ %F_%H-%M-%.SZ ] ';

# 2. Loop over a few DNS resolution attempts.
# cd -- "$( mktemp -d; )" &&
npm i --prefix "$( pwd -P; )" -- 'node-fetch' &&
node -v &&
node -- ./dns_latency.mjs 10 python.org mail front;
#! /usr/bin/env node
import fetch from 'node-fetch';
import dns from 'dns';
import util from 'util';
async function resolveDns(domain, subdomains) {
const resolutions = [];
for (const s of ['', ...subdomains]) {
const host = `${s}${s && '.'}${domain}`;
const startedAt = Date.now();
resolutions.push(await new Promise(r => dns.resolveAny(host, (_, v) => r(v))).then(resolved => ({
host,
latency: Date.now() - startedAt,
resolved,
})));
}
return resolutions;
}
async function main(args) {
const count = args.shift() || 0;
const domain = args.shift() || '';
const subdomains = args;
// IP address
// --------------------------------
await fetch('https://ipinfo.io/', {
method: 'post',
headers: {
'Content-Type': 'application/json',
'User-Agent': 'curl'
}
})
.then(r => r.text())
.then(console.log);
// DNS servers
// --------------------------------
console.log({ dns: dns.getServers() });
if (!/^(0|[1-9][0-9]*)$/.test(count) || count <= 0 || !domain?.length) {
return;
}
// DNS resolutions
// --------------------------------
const resolved = {
latencies: {},
addresses: {}
};
for (let i = 0; i < count; i++) {
const resolutions = await resolveDns(domain, subdomains);
console.log(
`[${new Date().toISOString()}] [${String(i).padStart(String(count).length, ' ')}/${count}]`,
util.inspect(resolutions, {
depth: 5,
breakLength: 200
}
));
resolutions.forEach(r => {
const latency = r.latency;
const address = r.resolved?.[0]?.address;
resolved.latencies[r.host] = resolved.latencies[r.host]?.concat(latency) || [latency];
resolved.addresses[r.host] = resolved.addresses[r.host]?.concat(address) || [address];
});
}
console.table(resolved.latencies);
console.table(resolved.addresses);
}
main(process.argv.slice(2));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment