Skip to content
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 CIDR blocks in no_proxy env variable #2876

Conversation

melkouri
Copy link
Contributor

@melkouri melkouri commented Jan 6, 2025

Issue created #2878

Issue:

The grpc-js lib doesn't support having CIDR blocks in the NO_PROXY variable (like 172.16.0.0/12
192.168.0.0/16). It only checks if the address we target is in the list of IPs in the NO_PROXY. Hence, it supposes that NO_PROXY is a list of single IPs.

For example if the NO_PROXY contains 192.168.0.0/16 and the IP you're trying to reach is 192.168.0.10. This latter is NOT considered in the range of the NO_PROXY because the lib just compares the IP to the elements of the NO_PROXY list.

We also want to support the case where we whitelist domain name suffixes in the NO_PROXY (like example.com, .internal., .local. ).

What is done in this PR:

  • Parse NO_PROXY list to get the ip and the prefix length of the CIDR
  • Check if targeted ip is in the range of the CIDR.
  • Check if targeted host contains the domain suffix.

Copy link

linux-foundation-easycla bot commented Jan 6, 2025

CLA Signed

The committers listed above are authorized under a signed CLA.

@melkouri melkouri marked this pull request as ready for review January 6, 2025 17:43
@melkouri melkouri marked this pull request as draft January 7, 2025 10:27
@melkouri melkouri marked this pull request as ready for review January 7, 2025 13:06
packages/grpc-js/src/http_proxy.ts Outdated Show resolved Hide resolved
for (const host of getNoProxyHostList()) {
const parsedCIDR = parseCIDR(host);
// host is a single IP address or a CIDR notation or a domain
if (parsedCIDR && isIpInCIDR(parsedCIDR, serverHost) || serverHost.endsWith(host)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The case where a non-IP serverHost string is passed to isIpInCIDR is not explicitly handled, making the result unclear. Either this line should avoid making that call, or isIpInCIDR should short-circuit return false if the serverHost is not an IP address, or ipToInt should return an error value if ip is not an IP address and isIpInCIDR should check for that value.

for (const host of getNoProxyHostList()) {
const parsedCIDR = parseCIDR(host);
// host is a single IP address or a CIDR notation or a domain
if (parsedCIDR && isIpInCIDR(parsedCIDR, serverHost) || serverHost.endsWith(host)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original logic uses host === serverHost to check for matches. That has been replaced here with serverHost.endsWith(host). That change is not related to supporting CIDR ranges, so it should be reverted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original logic where we handle single IPs is handled by isIpInCIDR(parsedCIDR, serverHost) as this latter transforms single IPs to CIDR notations (here).
This serverHost.endsWith(host) was to support the case where we include domain names/suffixes in the NO_PROXY (for example NO_PROXY=example.com,.local.,.local.).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case wasn't stated in the issue, I'll update it and make sure it's well handled in the code. Thank you for raising this 🙇

packages/grpc-js/src/http_proxy.ts Outdated Show resolved Hide resolved
packages/grpc-js/src/http_proxy.ts Outdated Show resolved Hide resolved
doc/environment_variables.md Outdated Show resolved Hide resolved
@melkouri melkouri requested a review from murgatroid99 January 9, 2025 11:14
@melkouri
Copy link
Contributor Author

melkouri commented Jan 9, 2025

Thank you @murgatroid99 for your review, I made some changes accordingly to your comments. I hope it's clearer 🙂

const parsedCIDR = parseCIDR(host);
// host is a single IP or a domain name suffix
if (!parsedCIDR) {
if (host === serverHost || serverHost.includes(host)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked and I see that other implementations support suffix matching, so I am OK with keeping the endsWith check here, but includes is definitely not correct. The equality check is also redundant with the substring check, so we should not have both.

packages/grpc-js/src/http_proxy.ts Outdated Show resolved Hide resolved
packages/grpc-js/src/http_proxy.ts Outdated Show resolved Hide resolved
packages/grpc-js/src/http_proxy.ts Outdated Show resolved Hide resolved
doc/environment_variables.md Outdated Show resolved Hide resolved
Copy link
Member

@murgatroid99 murgatroid99 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution, and for being patient through all of the reviews.

@murgatroid99 murgatroid99 merged commit 34b82cb into grpc:master Jan 15, 2025
3 of 5 checks passed
@melkouri
Copy link
Contributor Author

Thank you for the reviews!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants