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

Add filter state IP matcher #37637

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions api/envoy/type/matcher/v3/filter_state.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ package envoy.type.matcher.v3;

import "envoy/type/matcher/v3/string.proto";

import "xds/core/v3/cidr.proto";

import "udpa/annotations/status.proto";
import "validate/validate.proto";

Expand All @@ -25,5 +27,12 @@ message FilterStateMatcher {

// Matches the filter state object as a string value.
StringMatcher string_match = 2;

// Matches the filter state object as a ip Instance.
RepeatedCidrRange address_match = 3;
}
}

message RepeatedCidrRange {
repeated xds.core.v3.CidrRange range = 1;
}
antoniovleonti marked this conversation as resolved.
Show resolved Hide resolved
5 changes: 5 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,11 @@ new_features:
- area: grpc-json
change: |
Added a new http filter for :ref:`gRPC to JSON transcoding <config_http_filters_grpc_json_reverse_transcoder>`.
- area: matchers
change: |
Added new filter state matcher ip_range to
:ref:`FilterStateMatcher <envoy_api_msg_type.matcher.FilterStateMatcher>` which attempts to
cast the filter state object to an IP and match it against a list of CidrRanges.
- area: attributes
change: |
added new ``xds.virtual_host_name`` and ``xds.virtual_host_metadata`` attributes support. See
Expand Down
1 change: 1 addition & 0 deletions envoy/network/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ envoy_cc_library(
deps = [
"//envoy/common:base_includes",
"//envoy/common:pure_lib",
"//envoy/stream_info:filter_state_interface",
],
)

Expand Down
14 changes: 14 additions & 0 deletions envoy/network/address.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "envoy/common/platform.h"
#include "envoy/common/pure.h"
#include "envoy/stream_info/filter_state.h"

#include "absl/numeric/int128.h"
#include "absl/strings/string_view.h"
Expand Down Expand Up @@ -238,6 +239,19 @@ class Instance {
virtual const Network::SocketInterface& socketInterface() const PURE;
};

/*
* Used to store Instance in filter state.
*/
class InstanceConstSharedPtrAccessor : public Envoy::StreamInfo::FilterState::Object {
public:
InstanceConstSharedPtrAccessor(InstanceConstSharedPtr ip) : ip_(std::move(ip)) {}

InstanceConstSharedPtr getIp() const { return ip_; }

private:
InstanceConstSharedPtr ip_;
};

} // namespace Address
} // namespace Network
} // namespace Envoy
14 changes: 14 additions & 0 deletions source/common/common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ envoy_cc_library(
deps = [
":utility_lib",
"//envoy/common:matchers_interface",
"//source/common/common:filter_state_object_matchers_lib",
"//source/common/common:regex_lib",
"//source/common/config:metadata_lib",
"//source/common/config:utility_lib",
Expand All @@ -333,6 +334,19 @@ envoy_cc_library(
],
)

envoy_cc_library(
name = "filter_state_object_matchers_lib",
srcs = ["filter_state_object_matchers.cc"],
hdrs = ["filter_state_object_matchers.h"],
deps = [
"//envoy/common:exception_lib",
"//envoy/common:matchers_interface",
"//envoy/common:pure_lib",
"//source/common/network:cidr_range_interface",
"@com_google_absl//absl/status:statusor",
],
)

envoy_cc_library(
name = "random_generator_lib",
srcs = [
Expand Down
37 changes: 37 additions & 0 deletions source/common/common/filter_state_object_matchers.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include "source/common/common/filter_state_object_matchers.h"

#include "envoy/common/exception.h"
#include "envoy/network/address.h"
#include "envoy/stream_info/filter_state.h"

#include "source/common/network/cidr_range.h"

#include "absl/status/statusor.h"
#include "xds/core/v3/cidr.pb.h"

namespace Envoy {
namespace Matchers {

FilterStateIpRangeMatcher::FilterStateIpRangeMatcher(
std::unique_ptr<Network::Address::IpList>&& ip_list)
: ip_list_(std::move(ip_list)) {}

bool FilterStateIpRangeMatcher::match(const StreamInfo::FilterState::Object& object) const {
const Network::Address::InstanceConstSharedPtrAccessor* ip =
dynamic_cast<const Network::Address::InstanceConstSharedPtrAccessor*>(&object);
if (ip == nullptr) {
return false;
}
return ip_list_->contains(*ip->getIp());
}

FilterStateStringMatcher::FilterStateStringMatcher(StringMatcherPtr&& string_matcher)
: string_matcher_(std::move(string_matcher)) {}

bool FilterStateStringMatcher::match(const StreamInfo::FilterState::Object& object) const {
const auto string_value = object.serializeAsString();
return string_value && string_matcher_->match(*string_value);
}

} // namespace Matchers
} // namespace Envoy
41 changes: 41 additions & 0 deletions source/common/common/filter_state_object_matchers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include <memory>

#include "envoy/common/matchers.h"
#include "envoy/common/pure.h"
#include "envoy/stream_info/filter_state.h"

#include "source/common/network/cidr_range.h"

namespace Envoy {
namespace Matchers {

class FilterStateObjectMatcher {
public:
virtual bool match(const StreamInfo::FilterState::Object& object) const PURE;
virtual ~FilterStateObjectMatcher(){};
};

using FilterStateObjectMatcherPtr = std::unique_ptr<FilterStateObjectMatcher>;

class FilterStateIpRangeMatcher : public FilterStateObjectMatcher {
public:
FilterStateIpRangeMatcher(std::unique_ptr<Network::Address::IpList>&& ip_list);
bool match(const StreamInfo::FilterState::Object& object) const override;

private:
std::unique_ptr<Envoy::Network::Address::IpList> ip_list_;
};

class FilterStateStringMatcher : public FilterStateObjectMatcher {
public:
FilterStateStringMatcher(StringMatcherPtr&& string_matcher);
bool match(const StreamInfo::FilterState::Object& object) const override;

private:
const StringMatcherPtr string_matcher_;
};

} // namespace Matchers
} // namespace Envoy
42 changes: 33 additions & 9 deletions source/common/common/matchers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
#include "envoy/type/matcher/v3/string.pb.h"
#include "envoy/type/matcher/v3/value.pb.h"

#include "source/common/common/filter_state_object_matchers.h"
#include "source/common/common/macros.h"
#include "source/common/common/regex.h"
#include "source/common/config/metadata.h"
#include "source/common/config/utility.h"
#include "source/common/http/path_utility.h"

#include "absl/status/statusor.h"
#include "absl/strings/match.h"
#include "filter_state_object_matchers.h"

namespace Envoy {
namespace Matchers {
Expand Down Expand Up @@ -122,31 +125,52 @@ MetadataMatcher::MetadataMatcher(const envoy::type::matcher::v3::MetadataMatcher
}

namespace {
StringMatcherPtr valueMatcherFromProto(const envoy::type::matcher::v3::FilterStateMatcher& matcher,
Server::Configuration::CommonFactoryContext& context) {

absl::StatusOr<FilterStateObjectMatcherPtr>
filterStateObjectMatcherFromProto(const envoy::type::matcher::v3::FilterStateMatcher& matcher,
Server::Configuration::CommonFactoryContext& context) {
switch (matcher.matcher_case()) {
case envoy::type::matcher::v3::FilterStateMatcher::MatcherCase::kStringMatch:
return std::make_unique<const StringMatcherImpl<envoy::type::matcher::v3::StringMatcher>>(
matcher.string_match(), context);
return std::make_unique<FilterStateStringMatcher>(
std::make_unique<const StringMatcherImpl<envoy::type::matcher::v3::StringMatcher>>(
matcher.string_match(), context));
break;
case envoy::type::matcher::v3::FilterStateMatcher::MatcherCase::kAddressMatch: {
auto ip_list = Network::Address::IpList::create(matcher.address_match().range());
if (!ip_list.ok()) {
return ip_list.status();
}
return std::make_unique<FilterStateIpRangeMatcher>(std::move(*ip_list));
break;
}
default:
PANIC_DUE_TO_PROTO_UNSET;
}
}

} // namespace

FilterStateMatcher::FilterStateMatcher(const envoy::type::matcher::v3::FilterStateMatcher& matcher,
Server::Configuration::CommonFactoryContext& context)
: key_(matcher.key()), value_matcher_(valueMatcherFromProto(matcher, context)) {}
absl::StatusOr<FilterStateMatcherPtr>
FilterStateMatcher::create(const envoy::type::matcher::v3::FilterStateMatcher& config,
Server::Configuration::CommonFactoryContext& context) {
absl::StatusOr<FilterStateObjectMatcherPtr> matcher =
filterStateObjectMatcherFromProto(config, context);
if (!matcher.ok()) {
return matcher.status();
}
return std::make_unique<FilterStateMatcher>(config.key(), std::move(*matcher));
}

FilterStateMatcher::FilterStateMatcher(std::string key,
FilterStateObjectMatcherPtr&& object_matcher)
: key_(key), object_matcher_(std::move(object_matcher)) {}

bool FilterStateMatcher::match(const StreamInfo::FilterState& filter_state) const {
const auto* object = filter_state.getDataReadOnlyGeneric(key_);
if (object == nullptr) {
return false;
}
const auto string_value = object->serializeAsString();
return string_value && value_matcher_->match(*string_value);
return object_matcher_->match(*object);
}

PathMatcherConstSharedPtr
Expand Down
12 changes: 9 additions & 3 deletions source/common/common/matchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "envoy/type/matcher/v3/string.pb.h"
#include "envoy/type/matcher/v3/value.pb.h"

#include "source/common/common/filter_state_object_matchers.h"
#include "source/common/common/regex.h"
#include "source/common/common/utility.h"
#include "source/common/protobuf/protobuf.h"
Expand Down Expand Up @@ -239,8 +240,7 @@ class MetadataMatcher {

class FilterStateMatcher {
public:
FilterStateMatcher(const envoy::type::matcher::v3::FilterStateMatcher& matcher,
Server::Configuration::CommonFactoryContext& context);
FilterStateMatcher(std::string key, FilterStateObjectMatcherPtr&& object_matcher);

/**
* Check whether the filter state object is matched to the matcher.
Expand All @@ -249,11 +249,17 @@ class FilterStateMatcher {
*/
bool match(const StreamInfo::FilterState& filter_state) const;

static absl::StatusOr<std::unique_ptr<FilterStateMatcher>>
create(const envoy::type::matcher::v3::FilterStateMatcher& matcher,
Server::Configuration::CommonFactoryContext& context);

private:
const std::string key_;
const StringMatcherPtr value_matcher_;
const FilterStateObjectMatcherPtr object_matcher_;
};

using FilterStateMatcherPtr = std::unique_ptr<FilterStateMatcher>;

class PathMatcher : public StringMatcher {
public:
PathMatcher(const envoy::type::matcher::v3::PathMatcher& path,
Expand Down
22 changes: 22 additions & 0 deletions source/common/network/cidr_range.cc
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,15 @@ IpList::create(const Protobuf::RepeatedPtrField<envoy::config::core::v3::CidrRan
return ret;
}

absl::StatusOr<std::unique_ptr<IpList>>
IpList::create(const Protobuf::RepeatedPtrField<xds::core::v3::CidrRange>& cidrs) {
std::unique_ptr<IpList> ret = std::unique_ptr<IpList>(new IpList(cidrs));
if (!ret->error_.empty()) {
return absl::InvalidArgumentError(ret->error_);
}
return ret;
}

IpList::IpList(const Protobuf::RepeatedPtrField<envoy::config::core::v3::CidrRange>& cidrs) {
ip_list_.reserve(cidrs.size());
for (const envoy::config::core::v3::CidrRange& entry : cidrs) {
Expand All @@ -228,6 +237,19 @@ IpList::IpList(const Protobuf::RepeatedPtrField<envoy::config::core::v3::CidrRan
}
}

IpList::IpList(const Protobuf::RepeatedPtrField<xds::core::v3::CidrRange>& cidrs) {
ip_list_.reserve(cidrs.size());
for (const xds::core::v3::CidrRange& entry : cidrs) {
absl::StatusOr<CidrRange> range_or_error = CidrRange::create(entry);
if (range_or_error.status().ok()) {
ip_list_.push_back(std::move(range_or_error.value()));
} else {
error_ = fmt::format("invalid ip/mask combo '{}/{}' (format is <ip>/<# mask bits>)",
entry.address_prefix(), entry.prefix_len().value());
}
}
}

bool IpList::contains(const Instance& address) const {
for (const CidrRange& entry : ip_list_) {
if (entry.isInRange(address)) {
Expand Down
5 changes: 4 additions & 1 deletion source/common/network/cidr_range.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ class IpList {
public:
static absl::StatusOr<std::unique_ptr<IpList>>
create(const Protobuf::RepeatedPtrField<envoy::config::core::v3::CidrRange>& cidrs);
static absl::StatusOr<std::unique_ptr<IpList>>
create(const Protobuf::RepeatedPtrField<xds::core::v3::CidrRange>& cidrs);

IpList() = default;

Expand All @@ -140,7 +142,8 @@ class IpList {
const std::string& error() const { return error_; }

private:
explicit IpList(const Protobuf::RepeatedPtrField<envoy::config::core::v3::CidrRange>& cidrs);
IpList(const Protobuf::RepeatedPtrField<envoy::config::core::v3::CidrRange>& cidrs);
IpList(const Protobuf::RepeatedPtrField<xds::core::v3::CidrRange>& cidrs);
std::vector<CidrRange> ip_list_;
std::string error_;
};
Expand Down
7 changes: 6 additions & 1 deletion source/extensions/filters/common/rbac/matchers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,14 @@ bool MetadataMatcher::matches(const Network::Connection&, const Envoy::Http::Req
return matcher_.match(info.dynamicMetadata());
}

FilterStateMatcher::FilterStateMatcher(const envoy::type::matcher::v3::FilterStateMatcher& matcher,
Server::Configuration::CommonFactoryContext& context)
: matcher_(THROW_OR_RETURN_VALUE(Envoy::Matchers::FilterStateMatcher::create(matcher, context),
Envoy::Matchers::FilterStateMatcherPtr)) {}

bool FilterStateMatcher::matches(const Network::Connection&, const Envoy::Http::RequestHeaderMap&,
const StreamInfo::StreamInfo& info) const {
return matcher_.match(info.filterState());
return matcher_->match(info.filterState());
}

bool PolicyMatcher::matches(const Network::Connection& connection,
Expand Down
5 changes: 2 additions & 3 deletions source/extensions/filters/common/rbac/matchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,14 +263,13 @@ class MetadataMatcher : public Matcher {
class FilterStateMatcher : public Matcher {
public:
FilterStateMatcher(const envoy::type::matcher::v3::FilterStateMatcher& matcher,
Server::Configuration::CommonFactoryContext& context)
: matcher_(matcher, context) {}
Server::Configuration::CommonFactoryContext& context);

bool matches(const Network::Connection&, const Envoy::Http::RequestHeaderMap&,
const StreamInfo::StreamInfo& info) const override;

private:
const Envoy::Matchers::FilterStateMatcher matcher_;
const Envoy::Matchers::FilterStateMatcherPtr matcher_;
};

/**
Expand Down
Loading
Loading