Skip to content

Commit

Permalink
Merge pull request #2876 from melkouri/malak.elkouri/fix-grpc-js-no-p…
Browse files Browse the repository at this point in the history
…roxy-cidr-support

fix: support CIDR blocks in no_proxy env variable
  • Loading branch information
murgatroid99 authored Jan 15, 2025
2 parents 908c22a + 5e7cd85 commit 34b82cb
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 11 deletions.
8 changes: 5 additions & 3 deletions doc/environment_variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ can be set.
checked in order, and the first one that has a value is used.

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

* GRPC_SSL_CIPHER_SUITES
Expand Down Expand Up @@ -66,4 +68,4 @@ can be set.
* GRPC_NODE_USE_ALTERNATIVE_RESOLVER
Allows changing dns resolve behavior and parse DNS server authority as described in https://github.com/grpc/grpc/blob/master/doc/naming.md
- true - use alternative resolver
- false - use default resolver (default)
- false - use default resolver (default)
64 changes: 56 additions & 8 deletions packages/grpc-js/src/http_proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import { log } from './logging';
import { LogVerbosity } from './constants';
import { Socket } from 'net';
import { isIPv4, Socket } from 'net';
import * as http from 'http';
import * as logging from './logging';
import {
Expand Down Expand Up @@ -119,6 +119,58 @@ function getNoProxyHostList(): string[] {
}
}

interface CIDRNotation {
ip: number;
prefixLength: number;
}

/*
* The groups correspond to CIDR parts as follows:
* 1. ip
* 2. prefixLength
*/

export function parseCIDR(cidrString: string): CIDRNotation | null {
const splitRange = cidrString.split('/');
if (splitRange.length !== 2) {
return null;
}
const prefixLength = parseInt(splitRange[1], 10);
if (!isIPv4(splitRange[0]) || Number.isNaN(prefixLength) || prefixLength < 0 || prefixLength > 32) {
return null;
}
return {
ip: ipToInt(splitRange[0]),
prefixLength: prefixLength
};
}

function ipToInt(ip: string) {
return ip.split(".").reduce((acc, octet) => (acc << 8) + parseInt(octet, 10), 0);
}

function isIpInCIDR(cidr: CIDRNotation, serverHost: string) {
const ip = cidr.ip;
const mask = -1 << (32 - cidr.prefixLength);
const hostIP = ipToInt(serverHost);

return (hostIP & mask) === (ip & mask);
}

function hostMatchesNoProxyList(serverHost: string): boolean {
for (const host of getNoProxyHostList()) {
const parsedCIDR = parseCIDR(host);
// host is a CIDR and serverHost is an IP address
if (isIPv4(serverHost) && parsedCIDR && isIpInCIDR(parsedCIDR, serverHost)) {
return true;
} else if (serverHost.endsWith(host)) {
// host is a single IP or a domain name suffix
return true;
}
}
return false;
}

export interface ProxyMapResult {
target: GrpcUri;
extraOptions: ChannelOptions;
Expand Down Expand Up @@ -147,13 +199,9 @@ export function mapProxyName(
return noProxyResult;
}
const serverHost = hostPort.host;
for (const host of getNoProxyHostList()) {
if (host === serverHost) {
trace(
'Not using proxy for target in no_proxy list: ' + uriToString(target)
);
return noProxyResult;
}
if (hostMatchesNoProxyList(serverHost)) {
trace('Not using proxy for target in no_proxy list: ' + uriToString(target));
return noProxyResult;
}
const extraOptions: ChannelOptions = {
'grpc.http_connect_target': uriToString(target),
Expand Down

0 comments on commit 34b82cb

Please sign in to comment.