Line data Source code
1 : #include "source/common/network/address_impl.h"
2 :
3 : #include <array>
4 : #include <cstdint>
5 : #include <string>
6 :
7 : #include "envoy/common/exception.h"
8 : #include "envoy/common/platform.h"
9 :
10 : #include "source/common/common/assert.h"
11 : #include "source/common/common/fmt.h"
12 : #include "source/common/common/safe_memcpy.h"
13 : #include "source/common/common/thread.h"
14 : #include "source/common/common/utility.h"
15 : #include "source/common/network/socket_interface.h"
16 : #include "source/common/runtime/runtime_features.h"
17 :
18 : namespace Envoy {
19 : namespace Network {
20 : namespace Address {
21 :
22 : namespace {
23 :
24 : // Constructs a readable string with the embedded nulls in the abstract path replaced with '@'.
25 74 : std::string friendlyNameFromAbstractPath(absl::string_view path) {
26 74 : std::string friendly_name(path.data(), path.size());
27 74 : std::replace(friendly_name.begin(), friendly_name.end(), '\0', '@');
28 74 : return friendly_name;
29 74 : }
30 :
31 204131 : const SocketInterface* sockInterfaceOrDefault(const SocketInterface* sock_interface) {
32 204131 : return sock_interface == nullptr ? &SocketInterfaceSingleton::get() : sock_interface;
33 204131 : }
34 :
35 8315 : void throwOnError(absl::Status status) {
36 8315 : if (!status.ok()) {
37 0 : throwEnvoyExceptionOrPanic(status.ToString());
38 0 : }
39 8315 : }
40 :
41 3439 : InstanceConstSharedPtr throwOnError(StatusOr<InstanceConstSharedPtr> address) {
42 3439 : if (!address.ok()) {
43 0 : throwOnError(address.status());
44 0 : }
45 3439 : return *address;
46 3439 : }
47 :
48 : } // namespace
49 :
50 7915 : bool forceV6() {
51 : #if defined(__APPLE__) || defined(__ANDROID_API__)
52 : return Runtime::runtimeFeatureEnabled("envoy.reloadable_features.always_use_v6");
53 : #else
54 7915 : return false;
55 7915 : #endif
56 7915 : }
57 :
58 0 : void ipv6ToIpv4CompatibleAddress(const struct sockaddr_in6* sin6, struct sockaddr_in* sin) {
59 : #if defined(__APPLE__)
60 : *sin = {{}, AF_INET, sin6->sin6_port, {sin6->sin6_addr.__u6_addr.__u6_addr32[3]}, {}};
61 : #elif defined(WIN32)
62 : struct in_addr in_v4 = {};
63 : in_v4.S_un.S_addr = reinterpret_cast<const uint32_t*>(sin6->sin6_addr.u.Byte)[3];
64 : *sin = {AF_INET, sin6->sin6_port, in_v4, {}};
65 : #else
66 0 : *sin = {AF_INET, sin6->sin6_port, {sin6->sin6_addr.s6_addr32[3]}, {}};
67 0 : #endif
68 0 : }
69 :
70 : StatusOr<Address::InstanceConstSharedPtr> addressFromSockAddr(const sockaddr_storage& ss,
71 5275 : socklen_t ss_len, bool v6only) {
72 5275 : RELEASE_ASSERT(ss_len == 0 || static_cast<unsigned int>(ss_len) >= sizeof(sa_family_t), "");
73 5275 : if (forceV6()) {
74 0 : v6only = false;
75 0 : }
76 5275 : switch (ss.ss_family) {
77 5071 : case AF_INET: {
78 5071 : RELEASE_ASSERT(ss_len == 0 || static_cast<unsigned int>(ss_len) == sizeof(sockaddr_in), "");
79 5071 : const struct sockaddr_in* sin = reinterpret_cast<const struct sockaddr_in*>(&ss);
80 5071 : ASSERT(AF_INET == sin->sin_family);
81 5071 : return Address::InstanceFactory::createInstancePtr<Address::Ipv4Instance>(sin);
82 5071 : }
83 204 : case AF_INET6: {
84 204 : RELEASE_ASSERT(ss_len == 0 || static_cast<unsigned int>(ss_len) == sizeof(sockaddr_in6), "");
85 204 : const struct sockaddr_in6* sin6 = reinterpret_cast<const struct sockaddr_in6*>(&ss);
86 204 : ASSERT(AF_INET6 == sin6->sin6_family);
87 204 : if (!v6only && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
88 0 : struct sockaddr_in sin;
89 0 : ipv6ToIpv4CompatibleAddress(sin6, &sin);
90 0 : return Address::InstanceFactory::createInstancePtr<Address::Ipv4Instance>(&sin);
91 204 : } else {
92 204 : return Address::InstanceFactory::createInstancePtr<Address::Ipv6Instance>(*sin6, v6only);
93 204 : }
94 204 : }
95 0 : case AF_UNIX: {
96 0 : const struct sockaddr_un* sun = reinterpret_cast<const struct sockaddr_un*>(&ss);
97 0 : ASSERT(AF_UNIX == sun->sun_family);
98 0 : RELEASE_ASSERT(ss_len == 0 || static_cast<unsigned int>(ss_len) >=
99 0 : offsetof(struct sockaddr_un, sun_path) + 1,
100 0 : "");
101 0 : return Address::InstanceFactory::createInstancePtr<Address::PipeInstance>(sun, ss_len);
102 0 : }
103 0 : default:
104 0 : return absl::InvalidArgumentError(fmt::format("Unexpected sockaddr family: {}", ss.ss_family));
105 5275 : }
106 5275 : }
107 :
108 : Address::InstanceConstSharedPtr addressFromSockAddrOrThrow(const sockaddr_storage& ss,
109 3440 : socklen_t ss_len, bool v6only) {
110 : // Though we don't have any test coverage where address validation in addressFromSockAddr() fails,
111 : // this code is called in worker thread and can throw in theory. In that case, the program will
112 : // crash due to uncaught exception. In practice, we don't expect any address validation in
113 : // addressFromSockAddr() to fail in worker thread.
114 3440 : StatusOr<InstanceConstSharedPtr> address = addressFromSockAddr(ss, ss_len, v6only);
115 3440 : return throwOnError(address);
116 3440 : }
117 :
118 : Address::InstanceConstSharedPtr
119 1443 : addressFromSockAddrOrDie(const sockaddr_storage& ss, socklen_t ss_len, os_fd_t fd, bool v6only) {
120 : // Set v6only to false so that mapped-v6 address can be normalize to v4
121 : // address. Though dual stack may be disabled, it's still okay to assume the
122 : // address is from a dual stack socket. This is because mapped-v6 address
123 : // must come from a dual stack socket. An actual v6 address can come from
124 : // both dual stack socket and v6 only socket. If |peer_addr| is an actual v6
125 : // address and the socket is actually v6 only, the returned address will be
126 : // regarded as a v6 address from dual stack socket. However, this address is not going to be
127 : // used to create socket. Wrong knowledge of dual stack support won't hurt.
128 1443 : StatusOr<Address::InstanceConstSharedPtr> address =
129 1443 : Address::addressFromSockAddr(ss, ss_len, v6only);
130 1443 : if (!address.ok()) {
131 0 : PANIC(fmt::format("Invalid address for fd: {}, error: {}", fd, address.status().ToString()));
132 0 : }
133 1443 : return *address;
134 1443 : }
135 :
136 : Ipv4Instance::Ipv4Instance(const sockaddr_in* address, const SocketInterface* sock_interface)
137 0 : : InstanceBase(Type::Ip, sockInterfaceOrDefault(sock_interface)) {
138 0 : throwOnError(validateProtocolSupported());
139 0 : initHelper(address);
140 0 : }
141 :
142 : Ipv4Instance::Ipv4Instance(const std::string& address, const SocketInterface* sock_interface)
143 3700 : : Ipv4Instance(address, 0, sockInterfaceOrDefault(sock_interface)) {}
144 :
145 : Ipv4Instance::Ipv4Instance(const std::string& address, uint32_t port,
146 : const SocketInterface* sock_interface)
147 6685 : : InstanceBase(Type::Ip, sockInterfaceOrDefault(sock_interface)) {
148 6685 : throwOnError(validateProtocolSupported());
149 6685 : memset(&ip_.ipv4_.address_, 0, sizeof(ip_.ipv4_.address_));
150 6685 : ip_.ipv4_.address_.sin_family = AF_INET;
151 6685 : ip_.ipv4_.address_.sin_port = htons(port);
152 6685 : int rc = inet_pton(AF_INET, address.c_str(), &ip_.ipv4_.address_.sin_addr);
153 6685 : if (1 != rc) {
154 261 : throwEnvoyExceptionOrPanic(fmt::format("invalid ipv4 address '{}'", address));
155 261 : }
156 :
157 6424 : friendly_name_ = absl::StrCat(address, ":", port);
158 6424 : ip_.friendly_address_ = address;
159 6424 : }
160 :
161 : Ipv4Instance::Ipv4Instance(uint32_t port, const SocketInterface* sock_interface)
162 1204 : : InstanceBase(Type::Ip, sockInterfaceOrDefault(sock_interface)) {
163 1204 : throwOnError(validateProtocolSupported());
164 1204 : memset(&ip_.ipv4_.address_, 0, sizeof(ip_.ipv4_.address_));
165 1204 : ip_.ipv4_.address_.sin_family = AF_INET;
166 1204 : ip_.ipv4_.address_.sin_port = htons(port);
167 1204 : ip_.ipv4_.address_.sin_addr.s_addr = INADDR_ANY;
168 1204 : friendly_name_ = absl::StrCat("0.0.0.0:", port);
169 1204 : ip_.friendly_address_ = "0.0.0.0";
170 1204 : }
171 :
172 : Ipv4Instance::Ipv4Instance(absl::Status& status, const sockaddr_in* address,
173 : const SocketInterface* sock_interface)
174 190296 : : InstanceBase(Type::Ip, sockInterfaceOrDefault(sock_interface)) {
175 190296 : status = validateProtocolSupported();
176 190296 : if (!status.ok()) {
177 0 : return;
178 0 : }
179 190296 : initHelper(address);
180 190296 : }
181 :
182 18 : bool Ipv4Instance::operator==(const Instance& rhs) const {
183 18 : const Ipv4Instance* rhs_casted = dynamic_cast<const Ipv4Instance*>(&rhs);
184 18 : return (rhs_casted && (ip_.ipv4_.address() == rhs_casted->ip_.ipv4_.address()) &&
185 18 : (ip_.port() == rhs_casted->ip_.port()));
186 18 : }
187 :
188 190296 : std::string Ipv4Instance::sockaddrToString(const sockaddr_in& addr) {
189 190296 : static constexpr size_t BufferSize = 16; // enough space to hold an IPv4 address in string form
190 190296 : char str[BufferSize];
191 : // Write backwards from the end of the buffer for simplicity.
192 190296 : char* start = str + BufferSize;
193 190296 : uint32_t ipv4_addr = ntohl(addr.sin_addr.s_addr);
194 951480 : for (unsigned i = 4; i != 0; i--, ipv4_addr >>= 8) {
195 761184 : uint32_t octet = ipv4_addr & 0xff;
196 761184 : if (octet == 0) {
197 382013 : ASSERT(start > str);
198 382013 : *--start = '0';
199 382195 : } else {
200 755407 : do {
201 755407 : ASSERT(start > str);
202 755407 : *--start = '0' + (octet % 10);
203 755407 : octet /= 10;
204 755407 : } while (octet != 0);
205 379171 : }
206 761184 : if (i != 1) {
207 570888 : ASSERT(start > str);
208 570888 : *--start = '.';
209 570888 : }
210 761184 : }
211 190296 : const std::string::size_type end = str + BufferSize - start;
212 190296 : return {start, end};
213 190296 : }
214 :
215 198185 : absl::Status Ipv4Instance::validateProtocolSupported() {
216 198185 : static const bool supported = SocketInterfaceSingleton::get().ipFamilySupported(AF_INET);
217 198185 : if (supported) {
218 198185 : return absl::OkStatus();
219 198185 : }
220 0 : return absl::FailedPreconditionError("IPv4 addresses are not supported on this machine");
221 198185 : }
222 :
223 190296 : void Ipv4Instance::initHelper(const sockaddr_in* address) {
224 190296 : memset(&ip_.ipv4_.address_, 0, sizeof(ip_.ipv4_.address_));
225 190296 : ip_.ipv4_.address_ = *address;
226 190296 : ip_.friendly_address_ = sockaddrToString(*address);
227 :
228 : // Based on benchmark testing, this reserve+append implementation runs faster than absl::StrCat.
229 190296 : fmt::format_int port(ntohs(address->sin_port));
230 190296 : friendly_name_.reserve(ip_.friendly_address_.size() + 1 + port.size());
231 190296 : friendly_name_.append(ip_.friendly_address_);
232 190296 : friendly_name_.push_back(':');
233 190296 : friendly_name_.append(port.data(), port.size());
234 190296 : }
235 :
236 423 : absl::uint128 Ipv6Instance::Ipv6Helper::address() const {
237 423 : absl::uint128 result{0};
238 423 : static_assert(sizeof(absl::uint128) == 16, "The size of absl::uint128 is not 16.");
239 423 : safeMemcpyUnsafeSrc(&result, &address_.sin6_addr.s6_addr[0]);
240 423 : return result;
241 423 : }
242 :
243 98 : uint32_t Ipv6Instance::Ipv6Helper::scopeId() const { return address_.sin6_scope_id; }
244 :
245 1596 : uint32_t Ipv6Instance::Ipv6Helper::port() const { return ntohs(address_.sin6_port); }
246 :
247 515 : bool Ipv6Instance::Ipv6Helper::v6only() const { return v6only_; };
248 :
249 1081 : std::string Ipv6Instance::Ipv6Helper::makeFriendlyAddress() const {
250 1081 : char str[INET6_ADDRSTRLEN];
251 1081 : const char* ptr = inet_ntop(AF_INET6, &address_.sin6_addr, str, INET6_ADDRSTRLEN);
252 1081 : ASSERT(str == ptr);
253 1081 : if (address_.sin6_scope_id != 0) {
254 : // Note that here we don't use the `if_indextoname` that will give a more user friendly
255 : // output just because in the past created a performance bottleneck if the machine had a
256 : // lot of IPv6 Link local addresses.
257 98 : return absl::StrCat(ptr, "%", scopeId());
258 98 : }
259 983 : return ptr;
260 1081 : }
261 :
262 0 : InstanceConstSharedPtr Ipv6Instance::Ipv6Helper::v4CompatibleAddress() const {
263 0 : if (!v6only_ && IN6_IS_ADDR_V4MAPPED(&address_.sin6_addr)) {
264 0 : struct sockaddr_in sin;
265 0 : ipv6ToIpv4CompatibleAddress(&address_, &sin);
266 0 : auto addr = Address::InstanceFactory::createInstancePtr<Address::Ipv4Instance>(&sin);
267 0 : return addr.ok() ? addr.value() : nullptr;
268 0 : }
269 0 : return nullptr;
270 0 : }
271 :
272 0 : InstanceConstSharedPtr Ipv6Instance::Ipv6Helper::addressWithoutScopeId() const {
273 0 : struct sockaddr_in6 ret_addr = address_;
274 0 : ret_addr.sin6_scope_id = 0;
275 0 : auto addr = Address::InstanceFactory::createInstancePtr<Address::Ipv6Instance>(ret_addr, v6only_);
276 0 : return addr.ok() ? addr.value() : nullptr;
277 0 : }
278 :
279 : Ipv6Instance::Ipv6Instance(const sockaddr_in6& address, bool v6only,
280 : const SocketInterface* sock_interface)
281 0 : : InstanceBase(Type::Ip, sockInterfaceOrDefault(sock_interface)) {
282 0 : throwOnError(validateProtocolSupported());
283 0 : initHelper(address, v6only);
284 0 : }
285 :
286 : Ipv6Instance::Ipv6Instance(const std::string& address, const SocketInterface* sock_interface)
287 0 : : Ipv6Instance(address, 0, sockInterfaceOrDefault(sock_interface)) {}
288 :
289 : Ipv6Instance::Ipv6Instance(const std::string& address, uint32_t port,
290 : const SocketInterface* sock_interface, bool v6only)
291 426 : : InstanceBase(Type::Ip, sockInterfaceOrDefault(sock_interface)) {
292 426 : throwOnError(validateProtocolSupported());
293 426 : sockaddr_in6 addr_in;
294 426 : memset(&addr_in, 0, sizeof(addr_in));
295 426 : addr_in.sin6_family = AF_INET6;
296 426 : addr_in.sin6_port = htons(port);
297 426 : if (!address.empty()) {
298 3 : if (1 != inet_pton(AF_INET6, address.c_str(), &addr_in.sin6_addr)) {
299 0 : throwEnvoyExceptionOrPanic(fmt::format("invalid ipv6 address '{}'", address));
300 0 : }
301 426 : } else {
302 423 : addr_in.sin6_addr = in6addr_any;
303 423 : }
304 426 : initHelper(addr_in, v6only);
305 426 : }
306 :
307 : Ipv6Instance::Ipv6Instance(uint32_t port, const SocketInterface* sock_interface)
308 423 : : Ipv6Instance("", port, sockInterfaceOrDefault(sock_interface)) {}
309 :
310 0 : bool Ipv6Instance::operator==(const Instance& rhs) const {
311 0 : const auto* rhs_casted = dynamic_cast<const Ipv6Instance*>(&rhs);
312 0 : return (rhs_casted && (ip_.ipv6_.address() == rhs_casted->ip_.ipv6_.address()) &&
313 0 : (ip_.port() == rhs_casted->ip_.port()) &&
314 0 : (ip_.ipv6_.scopeId() == rhs_casted->ip_.ipv6_.scopeId()));
315 0 : }
316 :
317 : Ipv6Instance::Ipv6Instance(absl::Status& status, const sockaddr_in6& address, bool v6only,
318 : const SocketInterface* sock_interface)
319 655 : : InstanceBase(Type::Ip, sockInterfaceOrDefault(sock_interface)) {
320 655 : status = validateProtocolSupported();
321 655 : if (!status.ok()) {
322 0 : return;
323 0 : }
324 655 : initHelper(address, v6only);
325 655 : }
326 :
327 1081 : absl::Status Ipv6Instance::validateProtocolSupported() {
328 1081 : static const bool supported = SocketInterfaceSingleton::get().ipFamilySupported(AF_INET6);
329 1081 : if (supported) {
330 1081 : return absl::OkStatus();
331 1081 : }
332 0 : return absl::FailedPreconditionError("IPv6 addresses are not supported on this machine");
333 1081 : }
334 :
335 1081 : void Ipv6Instance::initHelper(const sockaddr_in6& address, bool v6only) {
336 1081 : ip_.ipv6_.address_ = address;
337 1081 : ip_.friendly_address_ = ip_.ipv6_.makeFriendlyAddress();
338 1081 : ip_.ipv6_.v6only_ = v6only;
339 1081 : friendly_name_ = fmt::format("[{}]:{}", ip_.friendly_address_, ip_.port());
340 1081 : }
341 :
342 : PipeInstance::PipeInstance(const sockaddr_un* address, socklen_t ss_len, mode_t mode,
343 : const SocketInterface* sock_interface)
344 0 : : InstanceBase(Type::Pipe, sockInterfaceOrDefault(sock_interface)) {
345 0 : if (address->sun_path[0] == '\0') {
346 : #if !defined(__linux__)
347 : throwEnvoyExceptionOrPanic("Abstract AF_UNIX sockets are only supported on linux.");
348 : #endif
349 0 : RELEASE_ASSERT(static_cast<unsigned int>(ss_len) >= offsetof(struct sockaddr_un, sun_path) + 1,
350 0 : "");
351 0 : pipe_.abstract_namespace_ = true;
352 0 : pipe_.address_length_ = ss_len - offsetof(struct sockaddr_un, sun_path);
353 0 : }
354 0 : absl::Status status = initHelper(address, mode);
355 0 : throwOnError(status);
356 0 : }
357 :
358 : PipeInstance::PipeInstance(const std::string& pipe_path, mode_t mode,
359 : const SocketInterface* sock_interface)
360 738 : : InstanceBase(Type::Pipe, sockInterfaceOrDefault(sock_interface)) {
361 738 : if (pipe_path.size() >= sizeof(pipe_.address_.sun_path)) {
362 201 : throwEnvoyExceptionOrPanic(
363 201 : fmt::format("Path \"{}\" exceeds maximum UNIX domain socket path size of {}.", pipe_path,
364 201 : sizeof(pipe_.address_.sun_path)));
365 201 : }
366 537 : memset(&pipe_.address_, 0, sizeof(pipe_.address_));
367 537 : pipe_.address_.sun_family = AF_UNIX;
368 537 : if (pipe_path[0] == '@') {
369 : // This indicates an abstract namespace.
370 : // In this case, null bytes in the name have no special significance, and so we copy all
371 : // characters of pipe_path to sun_path, including null bytes in the name. The pathname must also
372 : // be null terminated. The friendly name is the address path with embedded nulls replaced with
373 : // '@' for consistency with the first character.
374 : #if !defined(__linux__)
375 : throwEnvoyExceptionOrPanic("Abstract AF_UNIX sockets are only supported on linux.");
376 : #endif
377 74 : if (mode != 0) {
378 0 : throwEnvoyExceptionOrPanic("Cannot set mode for Abstract AF_UNIX sockets");
379 0 : }
380 74 : pipe_.abstract_namespace_ = true;
381 74 : pipe_.address_length_ = pipe_path.size();
382 : // The following statement is safe since pipe_path size was checked at the beginning of this
383 : // function
384 74 : memcpy(&pipe_.address_.sun_path[0], pipe_path.data(), pipe_path.size()); // NOLINT(safe-memcpy)
385 74 : pipe_.address_.sun_path[0] = '\0';
386 74 : pipe_.address_.sun_path[pipe_path.size()] = '\0';
387 74 : friendly_name_ = friendlyNameFromAbstractPath(
388 74 : absl::string_view(pipe_.address_.sun_path, pipe_.address_length_));
389 491 : } else {
390 : // Throw an error if the pipe path has an embedded null character.
391 463 : if (pipe_path.size() != strlen(pipe_path.c_str())) {
392 168 : throwEnvoyExceptionOrPanic("UNIX domain socket pathname contains embedded null characters");
393 168 : }
394 295 : StringUtil::strlcpy(&pipe_.address_.sun_path[0], pipe_path.c_str(),
395 295 : sizeof(pipe_.address_.sun_path));
396 295 : friendly_name_ = pipe_.address_.sun_path;
397 295 : }
398 369 : pipe_.mode_ = mode;
399 369 : }
400 :
401 : PipeInstance::PipeInstance(absl::Status& error, const sockaddr_un* address, socklen_t ss_len,
402 : mode_t mode, const SocketInterface* sock_interface)
403 0 : : InstanceBase(Type::Pipe, sockInterfaceOrDefault(sock_interface)) {
404 0 : if (address->sun_path[0] == '\0') {
405 : #if !defined(__linux__)
406 : error = absl::FailedPreconditionError("Abstract AF_UNIX sockets are only supported on linux.");
407 : return;
408 : #endif
409 0 : RELEASE_ASSERT(static_cast<unsigned int>(ss_len) >= offsetof(struct sockaddr_un, sun_path) + 1,
410 0 : "");
411 0 : pipe_.abstract_namespace_ = true;
412 0 : pipe_.address_length_ = ss_len - offsetof(struct sockaddr_un, sun_path);
413 0 : }
414 0 : error = initHelper(address, mode);
415 0 : }
416 :
417 0 : bool PipeInstance::operator==(const Instance& rhs) const { return asString() == rhs.asString(); }
418 :
419 0 : absl::Status PipeInstance::initHelper(const sockaddr_un* address, mode_t mode) {
420 0 : pipe_.address_ = *address;
421 0 : if (pipe_.abstract_namespace_) {
422 0 : if (mode != 0) {
423 0 : return absl::FailedPreconditionError("Cannot set mode for Abstract AF_UNIX sockets");
424 0 : }
425 : // Replace all null characters with '@' in friendly_name_.
426 0 : friendly_name_ = friendlyNameFromAbstractPath(
427 0 : absl::string_view(pipe_.address_.sun_path, pipe_.address_length_));
428 0 : } else {
429 0 : friendly_name_ = address->sun_path;
430 0 : }
431 0 : pipe_.mode_ = mode;
432 0 : return absl::OkStatus();
433 0 : }
434 :
435 : EnvoyInternalInstance::EnvoyInternalInstance(const std::string& address_id,
436 : const std::string& endpoint_id,
437 : const SocketInterface* sock_interface)
438 : : InstanceBase(Type::EnvoyInternal, sockInterfaceOrDefault(sock_interface)),
439 4 : internal_address_(address_id, endpoint_id) {
440 4 : friendly_name_ = absl::StrCat("envoy://", address_id, "/", endpoint_id);
441 4 : }
442 :
443 0 : bool EnvoyInternalInstance::operator==(const Instance& rhs) const {
444 0 : return rhs.type() == Type::EnvoyInternal && asString() == rhs.asString();
445 0 : }
446 :
447 : } // namespace Address
448 : } // namespace Network
449 : } // namespace Envoy
|