1
#pragma once
2

            
3
#include "envoy/extensions/matching/common_inputs/network/v3/network_inputs.pb.h"
4
#include "envoy/extensions/matching/common_inputs/network/v3/network_inputs.pb.validate.h"
5
#include "envoy/matcher/matcher.h"
6
#include "envoy/network/filter.h"
7
#include "envoy/registry/registry.h"
8

            
9
#include "source/common/common/logger.h"
10
#include "source/common/network/utility.h"
11

            
12
namespace Envoy {
13
namespace Network {
14
namespace Matching {
15

            
16
template <class InputType, class ProtoType, class MatchingDataType>
17
class BaseFactory : public Matcher::DataInputFactory<MatchingDataType> {
18
protected:
19
28943
  explicit BaseFactory(const std::string& name) : name_(name) {}
20

            
21
public:
22
185098
  std::string name() const override { return "envoy.matching.inputs." + name_; }
23

            
24
  Matcher::DataInputFactoryCb<MatchingDataType>
25
207
  createDataInputFactoryCb(const Protobuf::Message&, ProtobufMessage::ValidationVisitor&) override {
26
207
    return []() { return std::make_unique<InputType>(); };
27
207
  };
28
8465
  ProtobufTypes::MessagePtr createEmptyConfigProto() override {
29
8465
    return std::make_unique<ProtoType>();
30
8465
  }
31

            
32
private:
33
  const std::string name_;
34
};
35

            
36
template <class MatchingDataType>
37
class DestinationIPInput : public Matcher::DataInput<MatchingDataType> {
38
public:
39
27
  Matcher::DataInputGetResult get(const MatchingDataType& data) const override {
40
27
    const auto& address = data.localAddress();
41

            
42
27
    if (address.type() != Network::Address::Type::Ip) {
43
5
      return Matcher::DataInputGetResult::NoData();
44
5
    }
45
22
    const std::string& address_string = address.ip()->addressAsString();
46
22
    return Matcher::DataInputGetResult::CreateStringView(absl::string_view(address_string));
47
27
  }
48
};
49

            
50
template <class MatchingDataType>
51
class DestinationIPInputBaseFactory
52
    : public BaseFactory<
53
          DestinationIPInput<MatchingDataType>,
54
          envoy::extensions::matching::common_inputs::network::v3::DestinationIPInput,
55
          MatchingDataType> {
56
public:
57
  DestinationIPInputBaseFactory()
58
3945
      : BaseFactory<DestinationIPInput<MatchingDataType>,
59
3945
                    envoy::extensions::matching::common_inputs::network::v3::DestinationIPInput,
60
3945
                    MatchingDataType>("destination_ip") {}
61
};
62

            
63
DECLARE_FACTORY(DestinationIPInputFactory);
64
DECLARE_FACTORY(UdpDestinationIPInputFactory);
65
DECLARE_FACTORY(HttpDestinationIPInputFactory);
66

            
67
// With the support of generic matching API, integer is allowed in inputs such as
68
// `DestinationPortInput` and `SourcePortInput`. As a result, there is no longer a need for the
69
// redundant conversion of int-to-string. We can change them here once IntInputMatcher (for integer
70
// type input) is implemented.
71
template <class MatchingDataType>
72
class DestinationPortInput : public Matcher::DataInput<MatchingDataType> {
73
public:
74
67
  Matcher::DataInputGetResult get(const MatchingDataType& data) const override {
75
67
    const auto& address = data.localAddress();
76
67
    if (address.type() != Network::Address::Type::Ip) {
77
4
      return Matcher::DataInputGetResult::NoData();
78
4
    }
79
63
    return Matcher::DataInputGetResult::CreateString(absl::StrCat(address.ip()->port()));
80
67
  }
81
};
82

            
83
template <class MatchingDataType>
84
class DestinationPortInputBaseFactory
85
    : public BaseFactory<
86
          DestinationPortInput<MatchingDataType>,
87
          envoy::extensions::matching::common_inputs::network::v3::DestinationPortInput,
88
          MatchingDataType> {
89
public:
90
  DestinationPortInputBaseFactory()
91
3945
      : BaseFactory<DestinationPortInput<MatchingDataType>,
92
3945
                    envoy::extensions::matching::common_inputs::network::v3::DestinationPortInput,
93
3945
                    MatchingDataType>("destination_port") {}
94
};
95

            
96
DECLARE_FACTORY(DestinationPortInputFactory);
97
DECLARE_FACTORY(UdpDestinationPortInputFactory);
98
DECLARE_FACTORY(HttpDestinationPortInputFactory);
99

            
100
template <class MatchingDataType>
101
class SourceIPInput : public Matcher::DataInput<MatchingDataType> {
102
public:
103
43
  Matcher::DataInputGetResult get(const MatchingDataType& data) const override {
104
43
    const auto& address = data.remoteAddress();
105
43
    if (address.type() != Network::Address::Type::Ip) {
106
3
      return Matcher::DataInputGetResult::NoData();
107
3
    }
108
40
    const std::string& address_string = address.ip()->addressAsString();
109
40
    return Matcher::DataInputGetResult::CreateStringView(absl::string_view(address_string));
110
43
  }
111
};
112

            
113
template <class MatchingDataType>
114
class SourceIPInputBaseFactory
115
    : public BaseFactory<SourceIPInput<MatchingDataType>,
116
                         envoy::extensions::matching::common_inputs::network::v3::SourceIPInput,
117
                         MatchingDataType> {
118
public:
119
  SourceIPInputBaseFactory()
120
3945
      : BaseFactory<SourceIPInput<MatchingDataType>,
121
3945
                    envoy::extensions::matching::common_inputs::network::v3::SourceIPInput,
122
3945
                    MatchingDataType>("source_ip") {}
123
};
124

            
125
DECLARE_FACTORY(SourceIPInputFactory);
126
DECLARE_FACTORY(UdpSourceIPInputFactory);
127
DECLARE_FACTORY(HttpSourceIPInputFactory);
128

            
129
template <class MatchingDataType>
130
class SourcePortInput : public Matcher::DataInput<MatchingDataType> {
131
public:
132
20
  Matcher::DataInputGetResult get(const MatchingDataType& data) const override {
133
20
    const auto& address = data.remoteAddress();
134
20
    if (address.type() != Network::Address::Type::Ip) {
135
2
      return Matcher::DataInputGetResult::NoData();
136
2
    }
137
18
    return Matcher::DataInputGetResult::CreateString(absl::StrCat(address.ip()->port()));
138
20
  }
139
};
140

            
141
template <class MatchingDataType>
142
class SourcePortInputBaseFactory
143
    : public BaseFactory<SourcePortInput<MatchingDataType>,
144
                         envoy::extensions::matching::common_inputs::network::v3::SourcePortInput,
145
                         MatchingDataType> {
146
public:
147
  SourcePortInputBaseFactory()
148
3945
      : BaseFactory<SourcePortInput<MatchingDataType>,
149
3945
                    envoy::extensions::matching::common_inputs::network::v3::SourcePortInput,
150
3945
                    MatchingDataType>("source_port") {}
151
};
152

            
153
DECLARE_FACTORY(SourcePortInputFactory);
154
DECLARE_FACTORY(UdpSourcePortInputFactory);
155
DECLARE_FACTORY(HttpSourcePortInputFactory);
156

            
157
template <class MatchingDataType>
158
class DirectSourceIPInput : public Matcher::DataInput<MatchingDataType> {
159
public:
160
11
  Matcher::DataInputGetResult get(const MatchingDataType& data) const override {
161
11
    const auto& address = data.connectionInfoProvider().directRemoteAddress();
162
11
    if (address->type() != Network::Address::Type::Ip) {
163
3
      return Matcher::DataInputGetResult::NoData();
164
3
    }
165
8
    const std::string& address_string = address->ip()->addressAsString();
166
8
    return Matcher::DataInputGetResult::CreateStringView(absl::string_view(address_string));
167
11
  }
168
};
169

            
170
template <class MatchingDataType>
171
class DirectSourceIPInputBaseFactory
172
    : public BaseFactory<
173
          DirectSourceIPInput<MatchingDataType>,
174
          envoy::extensions::matching::common_inputs::network::v3::DirectSourceIPInput,
175
          MatchingDataType> {
176
public:
177
  DirectSourceIPInputBaseFactory()
178
2630
      : BaseFactory<DirectSourceIPInput<MatchingDataType>,
179
2630
                    envoy::extensions::matching::common_inputs::network::v3::DirectSourceIPInput,
180
2630
                    MatchingDataType>("direct_source_ip") {}
181
};
182

            
183
DECLARE_FACTORY(DirectSourceIPInputFactory);
184
DECLARE_FACTORY(HttpDirectSourceIPInputFactory);
185

            
186
inline constexpr absl::string_view Local = "local";
187

            
188
template <class MatchingDataType>
189
class SourceTypeInput : public Matcher::DataInput<MatchingDataType> {
190
public:
191
11
  Matcher::DataInputGetResult get(const MatchingDataType& data) const override {
192
11
    const bool is_local_connection =
193
11
        Network::Utility::isSameIpOrLoopback(data.connectionInfoProvider());
194
11
    if (is_local_connection) {
195
7
      return Matcher::DataInputGetResult::CreateStringView(Local);
196
7
    }
197
4
    return Matcher::DataInputGetResult::NoData();
198
11
  }
199
};
200

            
201
template <class MatchingDataType>
202
class SourceTypeInputBaseFactory
203
    : public BaseFactory<SourceTypeInput<MatchingDataType>,
204
                         envoy::extensions::matching::common_inputs::network::v3::SourceTypeInput,
205
                         MatchingDataType> {
206
public:
207
  SourceTypeInputBaseFactory()
208
2630
      : BaseFactory<SourceTypeInput<MatchingDataType>,
209
2630
                    envoy::extensions::matching::common_inputs::network::v3::SourceTypeInput,
210
2630
                    MatchingDataType>("source_type") {}
211
};
212

            
213
DECLARE_FACTORY(SourceTypeInputFactory);
214
DECLARE_FACTORY(HttpSourceTypeInputFactory);
215

            
216
template <class MatchingDataType>
217
class ServerNameInput : public Matcher::DataInput<MatchingDataType> {
218
public:
219
36
  Matcher::DataInputGetResult get(const MatchingDataType& data) const override {
220
36
    absl::string_view server_name = data.connectionInfoProvider().requestedServerName();
221
36
    if (!server_name.empty()) {
222
10
      return Matcher::DataInputGetResult::CreateStringView(server_name);
223
10
    }
224
26
    return Matcher::DataInputGetResult::NoData();
225
36
  }
226
};
227

            
228
template <class MatchingDataType>
229
class ServerNameInputBaseFactory
230
    : public BaseFactory<ServerNameInput<MatchingDataType>,
231
                         envoy::extensions::matching::common_inputs::network::v3::ServerNameInput,
232
                         MatchingDataType> {
233
public:
234
  ServerNameInputBaseFactory()
235
2630
      : BaseFactory<ServerNameInput<MatchingDataType>,
236
2630
                    envoy::extensions::matching::common_inputs::network::v3::ServerNameInput,
237
2630
                    MatchingDataType>("server_name") {}
238
};
239

            
240
DECLARE_FACTORY(ServerNameInputFactory);
241
DECLARE_FACTORY(HttpServerNameInputFactory);
242

            
243
class TransportProtocolInput : public Matcher::DataInput<MatchingData> {
244
public:
245
  Matcher::DataInputGetResult get(const MatchingData& data) const override;
246
};
247

            
248
class TransportProtocolInputFactory
249
    : public BaseFactory<
250
          TransportProtocolInput,
251
          envoy::extensions::matching::common_inputs::network::v3::TransportProtocolInput,
252
          MatchingData> {
253
public:
254
1315
  TransportProtocolInputFactory() : BaseFactory("transport_protocol") {}
255
};
256

            
257
DECLARE_FACTORY(TransportProtocolInputFactory);
258

            
259
template <class MatchingDataType>
260
class FilterStateInput : public Matcher::DataInput<MatchingDataType> {
261
public:
262
  FilterStateInput(const std::string& filter_state_key, const std::string& field = "")
263
31
      : filter_state_key_(filter_state_key), field_(field) {}
264

            
265
44
  Matcher::DataInputGetResult get(const MatchingDataType& data) const override {
266
44
    const auto* filter_state_object =
267
44
        data.filterState().template getDataReadOnly<StreamInfo::FilterState::Object>(
268
44
            filter_state_key_);
269

            
270
44
    if (filter_state_object != nullptr) {
271
      // If a field is specified and the object supports field access, use getField().
272
32
      if (!field_.empty() && filter_state_object->hasFieldSupport()) {
273
7
        const auto field_value = filter_state_object->getField(field_);
274
7
        if (absl::holds_alternative<absl::string_view>(field_value)) {
275
5
          return Matcher::DataInputGetResult::CreateStringView(
276
5
              absl::get<absl::string_view>(field_value));
277
5
        } else if (absl::holds_alternative<int64_t>(field_value)) {
278
          return Matcher::DataInputGetResult::CreateString(
279
              absl::StrCat(absl::get<int64_t>(field_value)));
280
        }
281
2
        return Matcher::DataInputGetResult::NoData();
282
7
      }
283

            
284
      // Default: return the serialized string representation of the whole object.
285
25
      auto str = filter_state_object->serializeAsString();
286
25
      if (str.has_value()) {
287
25
        return Matcher::DataInputGetResult::CreateString(std::move(str).value());
288
25
      } else {
289
        return Matcher::DataInputGetResult::NoData();
290
      }
291
25
    }
292

            
293
12
    return Matcher::DataInputGetResult::NoData();
294
44
  }
295

            
296
private:
297
  const std::string filter_state_key_;
298
  const std::string field_;
299
};
300

            
301
template <class MatchingDataType>
302
class FilterStateInputBaseFactory : public Matcher::DataInputFactory<MatchingDataType> {
303
public:
304
23974
  std::string name() const override { return "envoy.matching.inputs.filter_state"; }
305

            
306
  Matcher::DataInputFactoryCb<MatchingDataType>
307
  createDataInputFactoryCb(const Protobuf::Message& message,
308
20
                           ProtobufMessage::ValidationVisitor& validation_visitor) override {
309
20
    const auto& typed_config = MessageUtil::downcastAndValidate<
310
20
        const envoy::extensions::matching::common_inputs::network::v3::FilterStateInput&>(
311
20
        message, validation_visitor);
312

            
313
22
    return [filter_state_key = typed_config.key(), field = typed_config.field()] {
314
22
      return std::make_unique<FilterStateInput<MatchingDataType>>(filter_state_key, field);
315
22
    };
316
20
  };
317

            
318
989
  ProtobufTypes::MessagePtr createEmptyConfigProto() override {
319
989
    return std::make_unique<
320
989
        envoy::extensions::matching::common_inputs::network::v3::FilterStateInput>();
321
989
  }
322
};
323

            
324
DECLARE_FACTORY(FilterStateInputFactory);
325
DECLARE_FACTORY(HttpFilterStateInputFactory);
326

            
327
template <class MatchingDataType>
328
class NetworkNamespaceInput : public Matcher::DataInput<MatchingDataType>,
329
                              public Logger::Loggable<Logger::Id::matcher> {
330
public:
331
12
  Matcher::DataInputGetResult get(const MatchingDataType& data) const override {
332
12
    const auto& address = data.localAddress();
333
12
    auto network_namespace = address.networkNamespace();
334

            
335
12
    if (network_namespace.has_value() && !network_namespace->empty()) {
336
8
      ENVOY_LOG(debug, "NetworkNamespaceInput: local_address={} network_namespace='{}'",
337
8
                address.asString(), network_namespace.value());
338
8
      return Matcher::DataInputGetResult::CreateString(std::move(network_namespace).value());
339
8
    }
340

            
341
4
    ENVOY_LOG(debug, "NetworkNamespaceInput: no network namespace for local_address={}",
342
4
              address.asString());
343
4
    return Matcher::DataInputGetResult::NoData();
344
12
  }
345
};
346

            
347
template <class MatchingDataType>
348
class NetworkNamespaceInputBaseFactory
349
    : public BaseFactory<
350
          NetworkNamespaceInput<MatchingDataType>,
351
          envoy::extensions::matching::common_inputs::network::v3::NetworkNamespaceInput,
352
          MatchingDataType> {
353
public:
354
  NetworkNamespaceInputBaseFactory()
355
3945
      : BaseFactory<NetworkNamespaceInput<MatchingDataType>,
356
3945
                    envoy::extensions::matching::common_inputs::network::v3::NetworkNamespaceInput,
357
3945
                    MatchingDataType>("network_namespace") {}
358

            
359
  // Provide a literal factory name for static discovery by the extensions checker.
360
25289
  std::string name() const override { return "envoy.matching.inputs.network_namespace"; }
361
};
362

            
363
DECLARE_FACTORY(NetworkNamespaceInputFactory);
364
DECLARE_FACTORY(UdpNetworkNamespaceInputFactory);
365
DECLARE_FACTORY(HttpNetworkNamespaceInputFactory);
366

            
367
} // namespace Matching
368
} // namespace Network
369
} // namespace Envoy