Skip to content

Commit 34b82cb

Browse files
authored
Merge pull request #2876 from melkouri/malak.elkouri/fix-grpc-js-no-proxy-cidr-support
fix: support CIDR blocks in no_proxy env variable
2 parents 908c22a + 5e7cd85 commit 34b82cb

File tree

2 files changed

+61
-11
lines changed

2 files changed

+61
-11
lines changed

doc/environment_variables.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ can be set.
1111
checked in order, and the first one that has a value is used.
1212

1313
* no_grpc_proxy, no_proxy
14-
A comma separated list of hostnames to connect to without using a proxy even
15-
if a proxy is set. These variables are checked in order, and the first one
14+
A comma separated list of hostnames, IP addresses,
15+
or CIDR blocks to connect to without using a proxy even
16+
if a proxy is set, for example: no_proxy=example.com,192.168.0.1,192.168.0.0/16.
17+
These variables are checked in order, and the first one
1618
that has a value is used.
1719

1820
* GRPC_SSL_CIPHER_SUITES
@@ -66,4 +68,4 @@ can be set.
6668
* GRPC_NODE_USE_ALTERNATIVE_RESOLVER
6769
Allows changing dns resolve behavior and parse DNS server authority as described in https://github.com/grpc/grpc/blob/master/doc/naming.md
6870
- true - use alternative resolver
69-
- false - use default resolver (default)
71+
- false - use default resolver (default)

packages/grpc-js/src/http_proxy.ts

+56-8
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import { log } from './logging';
1919
import { LogVerbosity } from './constants';
20-
import { Socket } from 'net';
20+
import { isIPv4, Socket } from 'net';
2121
import * as http from 'http';
2222
import * as logging from './logging';
2323
import {
@@ -119,6 +119,58 @@ function getNoProxyHostList(): string[] {
119119
}
120120
}
121121

122+
interface CIDRNotation {
123+
ip: number;
124+
prefixLength: number;
125+
}
126+
127+
/*
128+
* The groups correspond to CIDR parts as follows:
129+
* 1. ip
130+
* 2. prefixLength
131+
*/
132+
133+
export function parseCIDR(cidrString: string): CIDRNotation | null {
134+
const splitRange = cidrString.split('/');
135+
if (splitRange.length !== 2) {
136+
return null;
137+
}
138+
const prefixLength = parseInt(splitRange[1], 10);
139+
if (!isIPv4(splitRange[0]) || Number.isNaN(prefixLength) || prefixLength < 0 || prefixLength > 32) {
140+
return null;
141+
}
142+
return {
143+
ip: ipToInt(splitRange[0]),
144+
prefixLength: prefixLength
145+
};
146+
}
147+
148+
function ipToInt(ip: string) {
149+
return ip.split(".").reduce((acc, octet) => (acc << 8) + parseInt(octet, 10), 0);
150+
}
151+
152+
function isIpInCIDR(cidr: CIDRNotation, serverHost: string) {
153+
const ip = cidr.ip;
154+
const mask = -1 << (32 - cidr.prefixLength);
155+
const hostIP = ipToInt(serverHost);
156+
157+
return (hostIP & mask) === (ip & mask);
158+
}
159+
160+
function hostMatchesNoProxyList(serverHost: string): boolean {
161+
for (const host of getNoProxyHostList()) {
162+
const parsedCIDR = parseCIDR(host);
163+
// host is a CIDR and serverHost is an IP address
164+
if (isIPv4(serverHost) && parsedCIDR && isIpInCIDR(parsedCIDR, serverHost)) {
165+
return true;
166+
} else if (serverHost.endsWith(host)) {
167+
// host is a single IP or a domain name suffix
168+
return true;
169+
}
170+
}
171+
return false;
172+
}
173+
122174
export interface ProxyMapResult {
123175
target: GrpcUri;
124176
extraOptions: ChannelOptions;
@@ -147,13 +199,9 @@ export function mapProxyName(
147199
return noProxyResult;
148200
}
149201
const serverHost = hostPort.host;
150-
for (const host of getNoProxyHostList()) {
151-
if (host === serverHost) {
152-
trace(
153-
'Not using proxy for target in no_proxy list: ' + uriToString(target)
154-
);
155-
return noProxyResult;
156-
}
202+
if (hostMatchesNoProxyList(serverHost)) {
203+
trace('Not using proxy for target in no_proxy list: ' + uriToString(target));
204+
return noProxyResult;
157205
}
158206
const extraOptions: ChannelOptions = {
159207
'grpc.http_connect_target': uriToString(target),

0 commit comments

Comments
 (0)