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 1 commit
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
5 changes: 5 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,8 @@ message FilterStateMatcher {

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

// Matchers the filter state object as a ip Instance.
xds.core.v3.CidrRange ip_range = 3;
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 @@ -335,6 +335,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
:ref:`ip_range <envoy_api_msg_type.matcher.v3.FilterStateMatcher.ip_range>` which attempts to cast
the filter state object to an IP and match it against a CIDR range.

deprecated:
- area: rbac
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
36 changes: 36 additions & 0 deletions source/common/common/filter_state_object_matchers.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#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(const Network::Address::CidrRange& cidr_range)
: cidr_range_(cidr_range) {}

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 cidr_range_.isInRange(*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(const Network::Address::CidrRange& cidr_range);
bool match(const StreamInfo::FilterState::Object& object) const override;

private:
Envoy::Network::Address::CidrRange cidr_range_;
};

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::kIpRange: {
auto ip_range = Network::Address::CidrRange::create(matcher.ip_range());
if (!ip_range.ok()) {
return ip_range.status();
}
return std::make_unique<FilterStateIpRangeMatcher>(*ip_range);
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
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