Skip to content

Commit

Permalink
fix: dns interceptor affinity
Browse files Browse the repository at this point in the history
* error was thrown when a single ip address was resolved
* `pick` always started on the second ip address if multiple
were resolved
* affinity was ignored with dual-stack
  • Loading branch information
luddd3 committed Oct 28, 2024
1 parent 2de0f34 commit e5a171b
Show file tree
Hide file tree
Showing 2 changed files with 607 additions and 33 deletions.
68 changes: 35 additions & 33 deletions lib/interceptor/dns.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ class DNSInstance {
affinity = null
lookup = null
pick = null
lastIpFamily = null

constructor (opts) {
this.#maxTTL = opts.maxTTL
Expand Down Expand Up @@ -61,9 +60,7 @@ class DNSInstance {
const ip = this.pick(
origin,
records,
// Only set affinity if dual stack is disabled
// otherwise let it go through normal flow
!newOpts.dualStack && newOpts.affinity
newOpts.affinity
)

cb(
Expand All @@ -78,9 +75,7 @@ class DNSInstance {
const ip = this.pick(
origin,
ips,
// Only set affinity if dual stack is disabled
// otherwise let it go through normal flow
!newOpts.dualStack && newOpts.affinity
newOpts.affinity
)

// If no IPs we lookup - deleting old records
Expand Down Expand Up @@ -123,36 +118,36 @@ class DNSInstance {

#defaultPick (origin, hostnameRecords, affinity) {
let ip = null
const { records, offset = 0 } = hostnameRecords
let newOffset = 0
const { records, offset } = hostnameRecords

let family
if (this.dualStack) {
if (affinity == null) {
// Balance between ip families
if (offset == null || offset === maxInt) {
hostnameRecords.offset = 0
affinity = 4
} else {
hostnameRecords.offset++
affinity = (hostnameRecords.offset & 1) === 1 ? 6 : 4
}
}

if (offset === maxInt) {
newOffset = 0
if (records[affinity] != null && records[affinity].ips.length > 0) {
family = records[affinity]
} else {
family = records[affinity === 4 ? 6 : 4]
}
} else {
newOffset = offset + 1
family = records[affinity]
}

// We balance between the two IP families
// If dual-stack disabled, we automatically pick the affinity
const newIpFamily = (newOffset & 1) === 1 ? 4 : 6
const family =
this.dualStack === false
? records[this.affinity] // If dual-stack is disabled, we pick the default affiniy
: records[affinity] ?? records[newIpFamily]

// If no IPs and we have tried both families or dual stack is disabled, we return null
if (
(family == null || family.ips.length === 0) &&
// eslint-disable-next-line eqeqeq
(this.dualStack === false || this.lastIpFamily != newIpFamily)
) {
// If no IPs we return null
if (family == null || family.ips.length === 0) {
return ip
}

family.offset = family.offset ?? 0
hostnameRecords.offset = newOffset

if (family.offset === maxInt) {
if (family.offset == null || family.offset === maxInt) {
family.offset = 0
} else {
family.offset++
Expand All @@ -172,7 +167,6 @@ class DNSInstance {
return this.pick(origin, hostnameRecords, affinity)
}

this.lastIpFamily = newIpFamily
return ip
}

Expand Down Expand Up @@ -301,12 +295,20 @@ module.exports = interceptorOpts => {
throw new InvalidArgumentError('Invalid pick. Must be a function')
}

const dualStack = interceptorOpts?.dualStack ?? true
let affinity
if (dualStack) {
affinity = interceptorOpts?.affinity ?? null
} else {
affinity = interceptorOpts?.affinity ?? 4
}

const opts = {
maxTTL: interceptorOpts?.maxTTL ?? 10e3, // Expressed in ms
lookup: interceptorOpts?.lookup ?? null,
pick: interceptorOpts?.pick ?? null,
dualStack: interceptorOpts?.dualStack ?? true,
affinity: interceptorOpts?.affinity ?? 4,
dualStack,
affinity,
maxItems: interceptorOpts?.maxItems ?? Infinity
}

Expand Down
Loading

0 comments on commit e5a171b

Please # to comment.