-
-
Notifications
You must be signed in to change notification settings - Fork 7
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
fix: support Node.js 20 #16
Conversation
} | ||
} | ||
}); | ||
|
||
it("should allow http://127.0.0.1, but other private ip is disallowed", async () => { | ||
const agent = new RequestFilteringHttpAgent({ | ||
allowIPAddressList: ["127.0.0.1"], | ||
allowIPAddressList: ["127.0.0.1", "::1"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
localhost will be ::1 in some env.
src/request-filtering-agent.ts
Outdated
socket.end(() => { | ||
console.log("end 2"); | ||
if (socket.destroyed) { | ||
return; | ||
} | ||
console.log("end 3 ", socket.destroyed); | ||
console.log("end errr", validationError?.message); | ||
socket.destroy(error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avoid Node.js ERR_INTERNAL_ASSERTION: end -> destory.
Just call destory
and Node.js throws ERR_INTERNAL_ASSERTION like #15
…direction` option
const privateIPs = [ | ||
`http://0.0.0.0:${TEST_PORT}`, // 0.0.0.0 is special |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move it to IPv4: should not request because it is meta/unspecified IP
src/request-filtering-agent.ts
Outdated
// override http.Agent#createConnection | ||
// https://nodejs.org/api/http.html#http_agent_createconnection_options_callback | ||
// https://nodejs.org/api/net.html#net_net_createconnection_options_connectlistener | ||
createConnection(options: TcpNetConnectOpts, connectionListener?: (error: Error | null, socket: Socket) => void) { | ||
const { host } = options; | ||
if (host !== undefined) { | ||
// Direct ip address request without dns-lookup | ||
// Example: http://127.0.0.1 | ||
// https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener | ||
const validationError = validateIPAddress({ address: host }, this.requestFilterOptions); | ||
if (validationError) { | ||
throw validationError; | ||
} | ||
} | ||
// https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener | ||
// @ts-expect-error - @types/node does not defined createConnection | ||
const socket: Socket = super.createConnection(options, connectionListener); | ||
// Request with domain name | ||
// Example: http://127.0.0.1.nip.io/ | ||
const onLookup = (err: Error, address: string, family: string | number, host: string): void => { | ||
if (err) { | ||
return; | ||
} | ||
const validationError = validateIPAddress({ address, family, host }, this.requestFilterOptions); | ||
if (validationError) { | ||
socket.removeListener("lookup", onLookup); | ||
socket.end(() => { | ||
socket.destroy(validationError); | ||
}); | ||
} | ||
}; | ||
socket.addListener("lookup", onLookup); | ||
return socket; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implement validation as Agent subclass.
Overriding instance(applyRequestFilter
) cause ERR_INTERNAL_ASSERTION on Node.js
We need to avoid this error.
src/request-filtering-agent.ts
Outdated
const validationError = validateIPAddress({ address, family, host }, this.requestFilterOptions); | ||
if (validationError) { | ||
socket.removeListener("lookup", onLookup); | ||
socket.end(() => { | ||
socket.destroy(validationError); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to call end
before destory
.
When just call destroy
without end
, Node.js 20 throws following error.
socket.destroy(validationError);
Error: This is caused by either a bug in Node.js or incorrect usage of Node.js internals.
Please open an issue with this stack trace at https://github.com/nodejs/node/issues
at new NodeError (node:internal/errors:406:5)
at assert (node:internal/assert:14:11)
at internalConnect (node:net:1037:3)
at defaultTriggerAsyncIdScope (node:internal/async_hooks:464:18)
at GetAddrInfoReqWrap.emitLookup [as callback] (node:net:1481:9)
at GetAddrInfoReqWrap.onlookupall [as oncomplete] (node:dns:130:8)
// prevent url redirection attack | ||
// connection not made to private IP adresses where the port is closed | ||
// Default: false | ||
stopPortScanningByUrlRedirection?: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
allowMetaIPAddress and allowPrivateIPAddress has same logics.
it("should fail to make request when stopPortScanningByUrlRedirection option is set to true", async () => { | ||
const closedPort = TEST_PORT + 1; | ||
const privateIPs = [ | ||
`http://0.0.0.0:${closedPort}`, // 0.0.0.0 is special | ||
`http://127.0.0.1:${closedPort}`, | ||
`http://[email protected]:${closedPort}` | ||
]; | ||
const agent = new RequestFilteringHttpAgent({ | ||
stopPortScanningByUrlRedirection: true | ||
}); | ||
for (const ipAddress of privateIPs) { | ||
try { | ||
await fetch(ipAddress, { | ||
agent, | ||
timeout: 2000 | ||
}); | ||
throw new ReferenceError("SHOULD NOT BE CALLED"); | ||
} catch (error) { | ||
if (error instanceof ReferenceError) { | ||
assert.fail(error); | ||
} | ||
assert.match( | ||
error.message, | ||
/^DNS lookup (0\.0\.0\.0|127\.0\.0\.1|undefined)\(family:undefined, host:(0\.0\.0\.0|127\.0\.0\.1|undefined)\) is not allowed. Because, It is private IP address.$/g | ||
); | ||
} | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test case is coverred by other tests.
TODO:
or patch updates?applyRequestFilter
Bug Fixes
v2.0.0 fixes following error on Node.js 20+
BREAKING CHANGE
applyRequestFilter(agent)
functionstopPortScanningByUrlRedirection
optionstopPortScanningByUrlRedirection
request-filtering-agent/test/request-filtering-agent.test.ts
Line 195 in a0a348e