Skip to content

Commit 2de0f34

Browse files
luddd3metcoder95
andauthored
fix: dns interceptor ip ttl (#3770)
Co-authored-by: Carlos Fuentes <[email protected]>
1 parent 2e79b62 commit 2de0f34

File tree

2 files changed

+138
-54
lines changed

2 files changed

+138
-54
lines changed

lib/interceptor/dns.js

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -111,15 +111,9 @@ class DNSInstance {
111111
const results = new Map()
112112

113113
for (const addr of addresses) {
114-
const record = {
115-
address: addr.address,
116-
ttl: opts.maxTTL,
117-
family: addr.family
118-
}
119-
120114
// On linux we found duplicates, we attempt to remove them with
121115
// the latest record
122-
results.set(`${record.address}:${record.family}`, record)
116+
results.set(`${addr.address}:${addr.family}`, addr)
123117
}
124118

125119
cb(null, results.values())
@@ -171,24 +165,29 @@ class DNSInstance {
171165
return ip
172166
}
173167

174-
const timestamp = Date.now()
175-
// Record TTL is already in ms
176-
if (ip.timestamp != null && timestamp - ip.timestamp > ip.ttl) {
168+
if (Date.now() - ip.timestamp > ip.ttl) { // record TTL is already in ms
177169
// We delete expired records
178170
// It is possible that they have different TTL, so we manage them individually
179171
family.ips.splice(position, 1)
180172
return this.pick(origin, hostnameRecords, affinity)
181173
}
182174

183-
ip.timestamp = timestamp
184-
185175
this.lastIpFamily = newIpFamily
186176
return ip
187177
}
188178

189179
setRecords (origin, addresses) {
180+
const timestamp = Date.now()
190181
const records = { records: { 4: null, 6: null } }
191182
for (const record of addresses) {
183+
record.timestamp = timestamp
184+
if (typeof record.ttl === 'number') {
185+
// The record TTL is expected to be in ms
186+
record.ttl = Math.min(record.ttl, this.#maxTTL)
187+
} else {
188+
record.ttl = this.#maxTTL
189+
}
190+
192191
const familyRecords = records.records[record.family] ?? { ips: [] }
193192

194193
familyRecords.ips.push(record)

test/interceptors/dns.js

Lines changed: 127 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ test('Should automatically resolve IPs (dual stack disabled - 6)', async t => {
500500
})
501501

502502
test('Should we handle TTL (4)', async t => {
503-
t = tspl(t, { plan: 7 })
503+
t = tspl(t, { plan: 10 })
504504

505505
let counter = 0
506506
let lookupCounter = 0
@@ -536,6 +536,10 @@ test('Should we handle TTL (4)', async t => {
536536
case 2:
537537
t.equal(isIP(url.hostname), 4)
538538
break
539+
540+
case 3:
541+
t.equal(isIP(url.hostname), 4)
542+
break
539543
default:
540544
t.fail('should not reach this point')
541545
}
@@ -546,31 +550,13 @@ test('Should we handle TTL (4)', async t => {
546550
dns({
547551
dualStack: false,
548552
affinity: 4,
549-
maxTTL: 100,
553+
maxTTL: 400,
550554
lookup: (origin, opts, cb) => {
551555
++lookupCounter
552556
lookup(
553557
origin.hostname,
554558
{ all: true, family: opts.affinity },
555-
(err, addresses) => {
556-
if (err) {
557-
return cb(err)
558-
}
559-
560-
const results = new Map()
561-
562-
for (const addr of addresses) {
563-
const record = {
564-
address: addr.address,
565-
ttl: opts.maxTTL,
566-
family: addr.family
567-
}
568-
569-
results.set(`${record.address}:${record.family}`, record)
570-
}
571-
572-
cb(null, results.values())
573-
}
559+
cb
574560
)
575561
}
576562
})
@@ -591,7 +577,7 @@ test('Should we handle TTL (4)', async t => {
591577
t.equal(response.statusCode, 200)
592578
t.equal(await response.body.text(), 'hello world!')
593579

594-
await sleep(500)
580+
await sleep(200)
595581

596582
const response2 = await client.request({
597583
...requestOptions,
@@ -600,11 +586,22 @@ test('Should we handle TTL (4)', async t => {
600586

601587
t.equal(response2.statusCode, 200)
602588
t.equal(await response2.body.text(), 'hello world!')
589+
590+
await sleep(300)
591+
592+
const response3 = await client.request({
593+
...requestOptions,
594+
origin: `http://localhost:${server.address().port}`
595+
})
596+
597+
t.equal(response3.statusCode, 200)
598+
t.equal(await response3.body.text(), 'hello world!')
599+
603600
t.equal(lookupCounter, 2)
604601
})
605602

606603
test('Should we handle TTL (6)', async t => {
607-
t = tspl(t, { plan: 7 })
604+
t = tspl(t, { plan: 10 })
608605

609606
let counter = 0
610607
let lookupCounter = 0
@@ -642,6 +639,11 @@ test('Should we handle TTL (6)', async t => {
642639
// [::1] -> ::1
643640
t.equal(isIP(url.hostname.slice(1, 4)), 6)
644641
break
642+
643+
case 3:
644+
// [::1] -> ::1
645+
t.equal(isIP(url.hostname.slice(1, 4)), 6)
646+
break
645647
default:
646648
t.fail('should not reach this point')
647649
}
@@ -652,35 +654,94 @@ test('Should we handle TTL (6)', async t => {
652654
dns({
653655
dualStack: false,
654656
affinity: 6,
655-
maxTTL: 100,
657+
maxTTL: 400,
656658
lookup: (origin, opts, cb) => {
657659
++lookupCounter
658660
lookup(
659661
origin.hostname,
660662
{ all: true, family: opts.affinity },
661-
(err, addresses) => {
662-
if (err) {
663-
return cb(err)
664-
}
663+
cb
664+
)
665+
}
666+
})
667+
])
668+
669+
after(async () => {
670+
await client.close()
671+
server.close()
665672

666-
const results = []
673+
await once(server, 'close')
674+
})
667675

668-
for (const addr of addresses) {
669-
const record = {
670-
address: addr.address,
671-
ttl: opts.maxTTL,
672-
family: addr.family
673-
}
676+
const response = await client.request({
677+
...requestOptions,
678+
origin: `http://localhost:${server.address().port}`
679+
})
680+
681+
t.equal(response.statusCode, 200)
682+
t.equal(await response.body.text(), 'hello world!')
683+
684+
await sleep(200)
685+
686+
const response2 = await client.request({
687+
...requestOptions,
688+
origin: `http://localhost:${server.address().port}`
689+
})
690+
691+
t.equal(response2.statusCode, 200)
692+
t.equal(await response2.body.text(), 'hello world!')
674693

675-
results.push(record)
676-
}
694+
await sleep(300)
677695

678-
cb(null, results)
696+
const response3 = await client.request({
697+
...requestOptions,
698+
origin: `http://localhost:${server.address().port}`
699+
})
700+
701+
t.equal(response3.statusCode, 200)
702+
t.equal(await response3.body.text(), 'hello world!')
703+
t.equal(lookupCounter, 2)
704+
})
705+
706+
test('Should set lowest TTL between resolved and option maxTTL', async t => {
707+
t = tspl(t, { plan: 9 })
708+
709+
let lookupCounter = 0
710+
const server = createServer()
711+
const requestOptions = {
712+
method: 'GET',
713+
path: '/',
714+
headers: {
715+
'content-type': 'application/json'
716+
}
717+
}
718+
719+
server.on('request', (req, res) => {
720+
res.writeHead(200, { 'content-type': 'text/plain' })
721+
res.end('hello world!')
722+
})
723+
724+
server.listen(0, '127.0.0.1')
725+
726+
await once(server, 'listening')
727+
728+
const client = new Agent().compose(
729+
dns({
730+
dualStack: false,
731+
affinity: 4,
732+
maxTTL: 200,
733+
lookup: (origin, opts, cb) => {
734+
++lookupCounter
735+
cb(null, [
736+
{
737+
address: '127.0.0.1',
738+
family: 4,
739+
ttl: lookupCounter === 1 ? 50 : 500
679740
}
680-
)
741+
])
681742
}
682743
})
683-
])
744+
)
684745

685746
after(async () => {
686747
await client.close()
@@ -697,16 +758,40 @@ test('Should we handle TTL (6)', async t => {
697758
t.equal(response.statusCode, 200)
698759
t.equal(await response.body.text(), 'hello world!')
699760

700-
await sleep(200)
761+
await sleep(100)
701762

763+
// 100ms: lookup since ttl = Math.min(50, maxTTL: 200)
702764
const response2 = await client.request({
703765
...requestOptions,
704766
origin: `http://localhost:${server.address().port}`
705767
})
706768

707769
t.equal(response2.statusCode, 200)
708770
t.equal(await response2.body.text(), 'hello world!')
709-
t.equal(lookupCounter, 2)
771+
772+
await sleep(100)
773+
774+
// 100ms: cached since ttl = Math.min(500, maxTTL: 200)
775+
const response3 = await client.request({
776+
...requestOptions,
777+
origin: `http://localhost:${server.address().port}`
778+
})
779+
780+
t.equal(response3.statusCode, 200)
781+
t.equal(await response3.body.text(), 'hello world!')
782+
783+
await sleep(150)
784+
785+
// 250ms: lookup since ttl = Math.min(500, maxTTL: 200)
786+
const response4 = await client.request({
787+
...requestOptions,
788+
origin: `http://localhost:${server.address().port}`
789+
})
790+
791+
t.equal(response4.statusCode, 200)
792+
t.equal(await response4.body.text(), 'hello world!')
793+
794+
t.equal(lookupCounter, 3)
710795
})
711796

712797
test('Should handle max cached items', async t => {

0 commit comments

Comments
 (0)