Skip to content

IP Matcher on a list of CIDR ranges#16592

Merged
snowp merged 23 commits intoenvoyproxy:mainfrom
curiefense:feature/ips_matcher
Jun 25, 2021
Merged

IP Matcher on a list of CIDR ranges#16592
snowp merged 23 commits intoenvoyproxy:mainfrom
curiefense:feature/ips_matcher

Conversation

@aguinet
Copy link
Contributor

@aguinet aguinet commented May 20, 2021

Commit Message: Input matcher that checks that an IP{v4,v6} belongs to a list of CIDR ranges
Additional Description:

This input matcher takes an IPv4 or v6 address as input and returns true if it belongs to a list of given CIDR ranges. It uses the existing LcTrie facility.

See issue #16568

Risk Level: Medium
Testing: Unit tests for the extension are added
Docs Changes: N/A
Release Notes: N/A
Platform Specific Features: N/A

Signed-off-by: Adrien Guinet <adrien@reblaze.com>
@repokitteh-read-only
Copy link

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to api/envoy/.
envoyproxy/api-shepherds assignee is @adisuissa
CC @envoyproxy/api-watchers: FYI only for changes made to api/envoy/.

🐱

Caused by: #16592 was opened by aguinet.

see: more, trace.

@aguinet
Copy link
Contributor Author

aguinet commented May 20, 2021

I have a question about https://github.com/envoyproxy/envoy/pull/16592/files#diff-2b3a93adfb5a23333aaf5113d8a99f142a8187735140781c49aeacd8c6c03795R23 : according to

/**
* TODO(ccaraman): Update CidrRange::create to support only constructing valid ranges.
* @return a CidrRange instance with the specified address and length, modified so that the only
* bits that might be non-zero are in the high-order length bits, and so that length is
* in the appropriate range (0 to 32 for IPv4, 0 to 128 for IPv6). If the address or
* length is invalid, then the range will be invalid (i.e. length == -1).
*/
static CidrRange create(InstanceConstSharedPtr address, int length);
static CidrRange create(const std::string& address, int length);
, CidrRange::create can return an invalid range, hence this check.

The "problem" is that I didn't manage to create such an invalid range. Indeed, if a invalid IP address prefix is given, Utility::parseInternetAddress throws an exception before CidrRange::create returns. If we give a too big prefix value, it is truncated by truncateIpAddressAndLength, and thus a valid range is returned. Finally, looking at

// static
CidrRange CidrRange::create(InstanceConstSharedPtr address, int length) {
InstanceConstSharedPtr ptr = truncateIpAddressAndLength(std::move(address), &length);
return CidrRange(std::move(ptr), length);
}
// static
CidrRange CidrRange::create(const std::string& address, int length) {
return create(Utility::parseInternetAddress(address), length);
}
and truncateIpAddressAndLength, I don't see how an invalid range could be returned, because parseInternetAddress will throw if it doesn't return an ipv4/ipv6 address (according to
Address::InstanceConstSharedPtr Utility::parseInternetAddressNoThrow(const std::string& ip_address,
uint16_t port, bool v6only) {
sockaddr_in sa4;
if (inet_pton(AF_INET, ip_address.c_str(), &sa4.sin_addr) == 1) {
sa4.sin_family = AF_INET;
sa4.sin_port = htons(port);
return std::make_shared<Address::Ipv4Instance>(&sa4);
}
sockaddr_in6 sa6;
memset(&sa6, 0, sizeof(sa6));
if (inet_pton(AF_INET6, ip_address.c_str(), &sa6.sin6_addr) == 1) {
sa6.sin6_family = AF_INET6;
sa6.sin6_port = htons(port);
return std::make_shared<Address::Ipv6Instance>(sa6, v6only);
}
return nullptr;
}
Address::InstanceConstSharedPtr Utility::parseInternetAddress(const std::string& ip_address,
uint16_t port, bool v6only) {
const Address::InstanceConstSharedPtr address =
parseInternetAddressNoThrow(ip_address, port, v6only);
if (address == nullptr) {
throwWithMalformedIp(ip_address);
}
return address;
}
).

Am I missing a corner case?

Thanks!

Copy link
Contributor

@adisuissa adisuissa left a comment

Choose a reason for hiding this comment

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

API review - overall looks good, couple of small comments.

// the paper `IP-address lookup using LC-tries
// <https://www.nada.kth.se/~snilsson/publications/IP-address-lookup-using-LC-tries/>`_
// by S. Nilsson and G. Karlsson.
message IP {
Copy link
Contributor

Choose a reason for hiding this comment

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

Naming convention suggests this should be Ip.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 16c5477

// <https://www.nada.kth.se/~snilsson/publications/IP-address-lookup-using-LC-tries/>`_
// by S. Nilsson and G. Karlsson.
message IP {
// Match if the IP belongs to any of these CIDR ranges
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: end comments with a period.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 16c5477 . Thanks for the review!

aguinet added 2 commits May 28, 2021 09:07
Review by @adisuissa

Signed-off-by: Adrien Guinet <adrien@reblaze.com>
Signed-off-by: Adrien Guinet <adrien@reblaze.com>
Copy link
Contributor

@adisuissa adisuissa left a comment

Choose a reason for hiding this comment

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

API looks good to me, and it is ready for the next round of reviews.
Please take a look at CI, as it seems legit.

Signed-off-by: Adrien Guinet <adrien@reblaze.com>
@aguinet
Copy link
Contributor Author

aguinet commented Jun 2, 2021

There's something I'm not sure I should fix in the CI: https://dev.azure.com/cncf/envoy/_build/results?buildId=77178&view=logs&j=91e633a5-4907-5da1-5862-92a79fe2387a&t=f29e24e7-a093-5724-80bd-d79975d268cb&l=295 tells me that I shouldn't add envoy.matching.input_matchers.ip to source/extensions/extensions_build_config.bzl, but I added it here: https://github.com/envoyproxy/envoy/pull/16592/files#diff-5294c859ad138c7624de53e0f9566c0b630f5a9522ff357d23b2f0b17d6e3991R55

Is there an error message I am missing? cc @adisuissa

aguinet added 2 commits June 2, 2021 19:31
Signed-off-by: Adrien Guinet <adrien@reblaze.com>
Signed-off-by: Adrien Guinet <adrien@reblaze.com>
Copy link
Contributor

@snowp snowp left a comment

Choose a reason for hiding this comment

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

Thanks for adding this! Looks pretty good overall, just a few comments

@snowp
Copy link
Contributor

snowp commented Jun 3, 2021

There's something I'm not sure I should fix in the CI: https://dev.azure.com/cncf/envoy/_build/results?buildId=77178&view=logs&j=91e633a5-4907-5da1-5862-92a79fe2387a&t=f29e24e7-a093-5724-80bd-d79975d268cb&l=295 tells me that I shouldn't add envoy.matching.input_matchers.ip to source/extensions/extensions_build_config.bzl, but I added it here: https://github.com/envoyproxy/envoy/pull/16592/files#diff-5294c859ad138c7624de53e0f9566c0b630f5a9522ff357d23b2f0b17d6e3991R55

Is there an error message I am missing? cc @adisuissa

cc @phlax

@phlax
Copy link
Member

phlax commented Jun 3, 2021

hi @aguinet - we can probs improve the error messaging here

the problem is that the extension needs to be added to source/extensions/extensions_metadata.yaml

the error is here https://dev.azure.com/cncf/envoy/_build/results?buildId=77574&view=logs&j=c5dd2866-6ab3-5f3c-3a44-4cef0ec909b5&t=a9eb66d6-8944-5769-b3f7-476949dadcb8&l=469

this interface/registration has just changed - so the ci link you posted is now out-of-date

@snowp snowp added the waiting label Jun 3, 2021
Signed-off-by: Adrien Guinet <adrien@reblaze.com>
Signed-off-by: Adrien Guinet <adrien@reblaze.com>
@aguinet
Copy link
Contributor Author

aguinet commented Jun 5, 2021

Thanks a lot @phlax for the hints! I added the extension to source/extensions/extensions_metadata.yaml.

aguinet added 5 commits June 8, 2021 21:03
Signed-off-by: Adrien Guinet <adrien@reblaze.com>
Signed-off-by: Adrien Guinet <adrien@reblaze.com>
Signed-off-by: Adrien Guinet <adrien@reblaze.com>
Signed-off-by: Adrien Guinet <adrien@reblaze.com>
Signed-off-by: Adrien Guinet <adrien@reblaze.com>
Copy link
Contributor

@snowp snowp left a comment

Choose a reason for hiding this comment

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

Thanks, this is looking good just a few more comments.

Could you also add a release note for this extension?

}

return std::make_unique<Matcher>(std::move(ranges));
const auto stat_prefix = ip_config.stat_prefix();
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: this incurs an additional copy, either const auto& or just pass this inline

Copy link
Contributor Author

@aguinet aguinet Jun 12, 2021

Choose a reason for hiding this comment

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

Fixed in 551ddcb , by using an explicit string_view

if (stats_) {
stats_->ip_parsing_failed_.inc();
}
ENVOY_LOG(warn, "IP matcher: unable to parse address '{}'", ip_str);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd suggest dropping down this down to debug or use one of the rate limited loggers, this could be extremely spammy if deployed with bad configuration which would impact proxy performance.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Dropped down to debug in 551ddcb

Comment on lines +29 to +30
// If specified, emits statistics using this prefix.
string stat_prefix = 2;
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we include docs that explain what stats are emitted? Normally we'd have a RST page explaining this extension, but I think inlining these docs in the proto file is fine for now

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7960aa3

Comment on lines +18 to +20
if (!stat_prefix.empty()) {
stats_.emplace(generateStats(stat_prefix, stat_scope));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think its more common to emit stats by default for extensions, so maybe make stats_prefix required so that it's always set? Or is there a good reason to avoid emitting this stat?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've seen this in another extension, so I just made the same :) I have no other rational than this, I'm happy to make it mandatory!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in 7960aa3 !

@aguinet
Copy link
Contributor Author

aguinet commented Jun 16, 2021

@snowp I merged with main.

I have a question though. In ff91bae#diff-2b3a93adfb5a23333aaf5113d8a99f142a8187735140781c49aeacd8c6c03795R30, is the reference to scope still valid when the callback is called? Thanks!

Edit: release note in ea28e0d

Signed-off-by: Adrien Guinet <adrien@reblaze.com>
@snowp
Copy link
Contributor

snowp commented Jun 17, 2021

Can you look at coverage? Seems like the build is failing due to this new code being slightly below the coverage threshold

/wait

Signed-off-by: Adrien Guinet <adrien@reblaze.com>
@aguinet
Copy link
Contributor Author

aguinet commented Jun 17, 2021

Can you look at coverage? Seems like the build is failing due to this new code being slightly below the coverage threshold

/wait

So the coverage problem is that I don't reach https://github.com/envoyproxy/envoy/pull/16592/files#diff-2b3a93adfb5a23333aaf5113d8a99f142a8187735140781c49aeacd8c6c03795R24 . It is basically the issue I explain here #16592 (comment) . I can remove the check, but I would like another POV on this :)

@snowp
Copy link
Contributor

snowp commented Jun 18, 2021

It seems like isValid just checks that the length is greater than 0, is it possible to hit that? If not, I think we can just replace it with an ASSERT with a comment explaining why this can't happen

@snowp snowp added the waiting label Jun 18, 2021
Signed-off-by: Adrien Guinet <adrien@reblaze.com>
@aguinet
Copy link
Contributor Author

aguinet commented Jun 20, 2021

It seems like isValid just checks that the length is greater than 0, is it possible to hit that? If not, I think we can just replace it with an ASSERT with a comment explaining why this can't happen

I didn't manage to hit it. We always at least have one IP (with /32 on ipv4 for instance). I added an ASSERT with a comment here ff53fe4

Copy link
Contributor

@adisuissa adisuissa left a comment

Choose a reason for hiding this comment

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

/lgtm api

Added a suggestion to clarify docs.


// The human readable prefix to use when emitting statistics for the IP input
// matcher.
//
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: clarify the the following counters will be concatenated to the stat_prefix

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in 5aaaa86

@snowp
Copy link
Contributor

snowp commented Jun 23, 2021

LGTM with @adisuissa's nit

Suggestion by @adisuissa

Signed-off-by: Adrien Guinet <adrien@reblaze.com>
@adisuissa
Copy link
Contributor

/lgtm api

@aguinet
Copy link
Contributor Author

aguinet commented Jun 24, 2021

Okay I forgot to regenerate the API.. Will fix it soon

Signed-off-by: Adrien Guinet <adrien@reblaze.com>
@aguinet
Copy link
Contributor Author

aguinet commented Jun 24, 2021

Okay I forgot to regenerate the API.. Will fix it soon

Fixed in 13fd781

Copy link
Contributor

@snowp snowp left a comment

Choose a reason for hiding this comment

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

Thanks!

@snowp snowp merged commit 6cd6a0c into envoyproxy:main Jun 25, 2021
@aguinet
Copy link
Contributor Author

aguinet commented Jun 25, 2021

Thanks for the merge and everyone for the reviews!

@aguinet aguinet deleted the feature/ips_matcher branch June 25, 2021 13:30
chrisxrepo pushed a commit to chrisxrepo/envoy that referenced this pull request Jul 8, 2021
Input matcher that checks that an IP{v4,v6} belongs to a list of CIDR ranges

Signed-off-by: Adrien Guinet <adrien@reblaze.com>
Signed-off-by: chris.xin <xinchuantao@qq.com>
leyao-daily pushed a commit to leyao-daily/envoy that referenced this pull request Sep 30, 2021
Input matcher that checks that an IP{v4,v6} belongs to a list of CIDR ranges

Signed-off-by: Adrien Guinet <adrien@reblaze.com>
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.

4 participants