diff --git a/packages/http-client/__tests__/proxy.test.ts b/packages/http-client/__tests__/proxy.test.ts index ddad334ee7..3659d26706 100644 --- a/packages/http-client/__tests__/proxy.test.ts +++ b/packages/http-client/__tests__/proxy.test.ts @@ -183,6 +183,13 @@ describe('proxy', () => { expect(bypass).toBeTruthy() }) + it('checkBypass supports CIDR in no_proxy', () => { + process.env['no_proxy'] = '10.0.0.0/8,fd00::/8,11.0.0.0/33,11.0.0.0/8/x' + expect(pm.checkBypass(new URL('http://10.1.2.3:8088'))).toBeTruthy() + expect(pm.checkBypass(new URL('http://[fd00::1]'))).toBeTruthy() + expect(pm.checkBypass(new URL('http://11.1.2.3'))).toBeFalsy() + }) + it('checkBypass returns true if no_proxy is "*"', () => { process.env['no_proxy'] = '*' const bypass = pm.checkBypass(new URL('https://anything.whatsoever.com')) diff --git a/packages/http-client/src/proxy.ts b/packages/http-client/src/proxy.ts index 3a9c6834ec..5009956f3e 100644 --- a/packages/http-client/src/proxy.ts +++ b/packages/http-client/src/proxy.ts @@ -1,3 +1,5 @@ +import {BlockList, isIP} from 'net' + export function getProxyUrl(reqUrl: URL): URL | undefined { const usingSsl = reqUrl.protocol === 'https:' @@ -69,7 +71,8 @@ export function checkBypass(reqUrl: URL): boolean { x.endsWith(`.${upperNoProxyItem}`) || (upperNoProxyItem.startsWith('.') && x.endsWith(`${upperNoProxyItem}`)) - ) + ) || + matchesCidr(reqHost.replace(/^\[|\]$/g, ''), upperNoProxyItem) ) { return true } @@ -88,6 +91,19 @@ function isLoopbackAddress(host: string): boolean { ) } +function matchesCidr(ip: string, cidr: string): boolean { + const [network, prefix, extra] = cidr.split('/') + if (!prefix || extra !== undefined || !isIP(ip)) return false + + const blockList = new BlockList() + try { + blockList.addSubnet(network, +prefix, isIP(network) === 6 ? 'ipv6' : 'ipv4') + return blockList.check(ip, isIP(ip) === 6 ? 'ipv6' : 'ipv4') + } catch { + return false + } +} + class DecodedURL extends URL { private _decodedUsername: string private _decodedPassword: string