1
#pragma once
2

            
3
#include <cstddef>
4
#include <string>
5
#include <vector>
6

            
7
#include "envoy/config/core/v3/address.pb.h"
8
#include "envoy/network/address.h"
9

            
10
#include "source/common/protobuf/protobuf.h"
11

            
12
#include "xds/core/v3/cidr.pb.h"
13

            
14
namespace Envoy {
15
namespace Network {
16
namespace Address {
17

            
18
/**
19
 * A "Classless Inter-Domain Routing" range of internet addresses, aka a CIDR range, consisting
20
 * of an Ip address and a count of leading bits included in the mask. Other than those leading
21
 * bits, all of the other bits of the Ip address are zero. For more info, see RFC1519 or
22
 * https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing.
23
 */
24
class CidrRange {
25
public:
26
  /**
27
   * Constructs an uninitialized range: length == -1, and there is no associated address.
28
   */
29
  CidrRange();
30

            
31
2191796
  CidrRange(const CidrRange& other) = default;
32
193346
  CidrRange(CidrRange&& other) = default;
33

            
34
  /**
35
   * Overwrites this with other.
36
   */
37
  CidrRange& operator=(const CidrRange& other);
38

            
39
  /**
40
   * @return true if the ranges are identical.
41
   */
42
  bool operator==(const CidrRange& other) const;
43

            
44
  /**
45
   * @return Ip address data IFF length >= 0, otherwise nullptr.
46
   */
47
  const Ip* ip() const;
48

            
49
  /**
50
   * TODO(jamessynge) Consider making this absl::optional<int> length, or modifying the create()
51
   * methods below to return absl::optional<CidrRange> (the latter is probably better).
52
   * @return the number of bits of the address that are included in the mask. -1 if uninitialized
53
   *         or invalid, else in the range 0 to 32 for IPv4, and 0 to 128 for IPv6.
54
   */
55
  int length() const;
56

            
57
  /**
58
   * @return true if the address argument is in the range of this object, false if not, including
59
             if the range is uninitialized or if the argument is not of the same IpVersion.
60
   */
61
  bool isInRange(const Instance& address) const;
62

            
63
  /**
64
   * @return a human readable string for the range. This string will be in the following format:
65
   *         - For IPv4 ranges: "1.2.3.4/32" or "10.240.0.0/16"
66
   *         - For IPv6 ranges: "1234:5678::f/128" or "1234:5678::/64"
67
   */
68
  std::string asString() const;
69

            
70
  /**
71
   * @return a CidrRange instance with the specified address and length, modified so that the only
72
   *         bits that might be non-zero are in the high-order length bits, and so that length is
73
   *         in the appropriate range (0 to 32 for IPv4, 0 to 128 for IPv6). If the address or
74
   *         length is invalid, then the range will be invalid (i.e. length == -1).
75
   */
76
  static absl::StatusOr<CidrRange>
77
  create(InstanceConstSharedPtr address, int length,
78
         absl::optional<absl::string_view> original_address_str = "");
79
  static absl::StatusOr<CidrRange> create(const std::string& address, int length);
80

            
81
  /**
82
   * Constructs an CidrRange from a string with this format (same as returned
83
   * by CidrRange::asString above):
84
   *      <address>/<length>    e.g. "10.240.0.0/16" or "1234:5678::/64"
85
   * @return a CidrRange instance with the specified address and length if parsed successfully,
86
   *         else with no address and a length of -1.
87
   */
88
  static absl::StatusOr<CidrRange> create(const std::string& range);
89

            
90
  /**
91
   * Constructs a CidrRange from envoy::config::core::v3::CidrRange.
92
   */
93
  static absl::StatusOr<CidrRange> create(const envoy::config::core::v3::CidrRange& cidr);
94

            
95
  /**
96
   * Constructs a CidrRange from xds::core::v3::CidrRange.
97
   */
98
  static absl::StatusOr<CidrRange> create(const xds::core::v3::CidrRange& cidr);
99

            
100
  /**
101
   * Given an IP address and a length of high order bits to keep, returns an address
102
   * where those high order bits are unmodified, and the remaining bits are all zero.
103
   * length_io is reduced to be at most 32 for IPv4 address and at most 128 for IPv6
104
   * addresses. If the address is invalid or the length is less than zero, then *length_io
105
   * is set to -1 and nullptr is returned.
106
   * @return a pointer to an address where the high order *length_io bits are unmodified
107
   *         from address, and *length_io is in the range 0 to N, where N is the number of bits
108
   *         in an address of the IP version (i.e. address->ip()->version()).
109
   */
110
  static InstanceConstSharedPtr truncateIpAddressAndLength(InstanceConstSharedPtr address,
111
                                                           int* length_io);
112

            
113
private:
114
  /**
115
   * @return true if this instance is valid; address != nullptr && length is appropriate for the
116
   *         IP version (these are checked during construction, and reduced down to a check of
117
   *         the length).
118
   */
119
98945
  bool isValid() const { return length_ >= 0; }
120

            
121
  CidrRange(InstanceConstSharedPtr address, int length);
122

            
123
  InstanceConstSharedPtr address_;
124
  int length_;
125
};
126

            
127
/**
128
 * Class for keeping a list of CidrRanges, and then determining whether an
129
 * IP address is in the CidrRange list.
130
 */
131
class IpList {
132
public:
133
  static absl::StatusOr<std::unique_ptr<IpList>>
134
  create(const Protobuf::RepeatedPtrField<envoy::config::core::v3::CidrRange>& cidrs);
135
  static absl::StatusOr<std::unique_ptr<IpList>>
136
  create(const Protobuf::RepeatedPtrField<xds::core::v3::CidrRange>& cidrs);
137

            
138
73
  IpList() = default;
139

            
140
  bool contains(const Instance& address) const;
141
1421
  size_t getIpListSize() const { return ip_list_.size(); };
142
  const std::string& error() const { return error_; }
143

            
144
private:
145
  IpList(const Protobuf::RepeatedPtrField<envoy::config::core::v3::CidrRange>& cidrs);
146
  IpList(const Protobuf::RepeatedPtrField<xds::core::v3::CidrRange>& cidrs);
147
  std::vector<CidrRange> ip_list_;
148
  std::string error_;
149
};
150

            
151
} // namespace Address
152
} // namespace Network
153
} // namespace Envoy