Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/common/network/utility.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <cstdint>
4
#include <list>
5
#include <string>
6
7
#include "envoy/common/platform.h"
8
#include "envoy/config/core/v3/address.pb.h"
9
#include "envoy/network/connection.h"
10
#include "envoy/network/listener.h"
11
12
#include "source/common/common/statusor.h"
13
14
#include "absl/strings/string_view.h"
15
16
namespace Envoy {
17
namespace Network {
18
19
/**
20
 * Utility class to represent TCP/UDP port range
21
 */
22
class PortRange {
23
public:
24
0
  PortRange(uint32_t min, uint32_t max) : min_(min), max_(max) {}
25
26
0
  bool contains(uint32_t port) const { return (port >= min_ && port <= max_); }
27
28
private:
29
  const uint32_t min_;
30
  const uint32_t max_;
31
};
32
33
using PortRangeList = std::list<PortRange>;
34
35
/**
36
 * A callback interface used by readFromSocket() to pass packets read from
37
 * socket.
38
 */
39
class UdpPacketProcessor {
40
public:
41
0
  virtual ~UdpPacketProcessor() = default;
42
43
  /**
44
   * Consume the packet read out of the socket with the information from UDP
45
   * header.
46
   * @param local_address is the destination address in the UDP header.
47
   * @param peer_address is the source address in the UDP header.
48
   * @param buffer contains the packet read.
49
   * @param receive_time is the time when the packet is read.
50
   */
51
  virtual void processPacket(Address::InstanceConstSharedPtr local_address,
52
                             Address::InstanceConstSharedPtr peer_address,
53
                             Buffer::InstancePtr buffer, MonotonicTime receive_time) PURE;
54
55
  /**
56
   * Called whenever datagrams are dropped due to overflow or truncation.
57
   * @param dropped supplies the number of dropped datagrams.
58
   */
59
  virtual void onDatagramsDropped(uint32_t dropped) PURE;
60
61
  /**
62
   * The expected max size of the datagram to be read. If it's smaller than
63
   * the size of datagrams received, they will be dropped.
64
   */
65
  virtual uint64_t maxDatagramSize() const PURE;
66
67
  /**
68
   * An estimated number of packets to read in each read event.
69
   */
70
  virtual size_t numPacketsExpectedPerEventLoop() const PURE;
71
};
72
73
static const uint64_t DEFAULT_UDP_MAX_DATAGRAM_SIZE = 1500;
74
static const uint64_t NUM_DATAGRAMS_PER_RECEIVE = 16;
75
static const uint64_t MAX_NUM_PACKETS_PER_EVENT_LOOP = 6000;
76
77
/**
78
 * Wrapper which resolves UDP socket proto config with defaults.
79
 */
80
struct ResolvedUdpSocketConfig {
81
  ResolvedUdpSocketConfig(const envoy::config::core::v3::UdpSocketConfig& config,
82
                          bool prefer_gro_default);
83
84
  uint64_t max_rx_datagram_size_;
85
  bool prefer_gro_;
86
};
87
88
/**
89
 * Common network utility routines.
90
 */
91
class Utility {
92
public:
93
  static constexpr absl::string_view TCP_SCHEME{"tcp://"};
94
  static constexpr absl::string_view UDP_SCHEME{"udp://"};
95
  static constexpr absl::string_view UNIX_SCHEME{"unix://"};
96
97
  /**
98
   * Make a URL from a datagram Address::Instance; will be udp:// prefix for
99
   * an IP address, and unix:// prefix otherwise. Giving a tcp address to this
100
   * function will result in incorrect behavior (addresses don't know if they
101
   * are datagram or stream).
102
   * @param addr supplies the address to convert to string.
103
   * @return The appropriate url string compatible with resolveUrl.
104
   */
105
  static std::string urlFromDatagramAddress(const Address::Instance& addr);
106
107
  /**
108
   * Resolve a URL.
109
   * @param url supplies the url to resolve.
110
   * @return Address::InstanceConstSharedPtr the resolved address.
111
   * @throw EnvoyException if url is invalid.
112
   */
113
  static Address::InstanceConstSharedPtr resolveUrl(const std::string& url);
114
115
  /**
116
   * Determine the socket type for a URL.
117
   *
118
   * @param url supplies the url to resolve.
119
   * @return StatusOr<Socket::Type> of the socket type, or an error status if url is invalid.
120
   */
121
  static StatusOr<Socket::Type> socketTypeFromUrl(const std::string& url);
122
123
  /**
124
   * Match a URL to the TCP scheme
125
   * @param url supplies the URL to match.
126
   * @return bool true if the URL matches the TCP scheme, false otherwise.
127
   */
128
  static bool urlIsTcpScheme(absl::string_view url);
129
130
  /**
131
   * Match a URL to the UDP scheme
132
   * @param url supplies the URL to match.
133
   * @return bool true if the URL matches the UDP scheme, false otherwise.
134
   */
135
  static bool urlIsUdpScheme(absl::string_view url);
136
137
  /**
138
   * Match a URL to the Unix scheme
139
   * @param url supplies the Unix to match.
140
   * @return bool true if the URL matches the Unix scheme, false otherwise.
141
   */
142
  static bool urlIsUnixScheme(absl::string_view url);
143
144
  /**
145
   * Parse an internet host address (IPv4 or IPv6) and create an Instance from it. The address must
146
   * not include a port number. Throws EnvoyException if unable to parse the address.
147
   * @param ip_address string to be parsed as an internet address.
148
   * @param port optional port to include in Instance created from ip_address, 0 by default.
149
   * @param v6only disable IPv4-IPv6 mapping for IPv6 addresses?
150
   * @return pointer to the Instance.
151
   * @throw EnvoyException in case of a malformed IP address.
152
   */
153
  static Address::InstanceConstSharedPtr
154
  parseInternetAddress(const std::string& ip_address, uint16_t port = 0, bool v6only = true);
155
156
  /**
157
   * Parse an internet host address (IPv4 or IPv6) and create an Instance from it. The address must
158
   * not include a port number.
159
   * @param ip_address string to be parsed as an internet address.
160
   * @param port optional port to include in Instance created from ip_address, 0 by default.
161
   * @param v6only disable IPv4-IPv6 mapping for IPv6 addresses?
162
   * @return pointer to the Instance, or nullptr if unable to parse the address.
163
   */
164
  static Address::InstanceConstSharedPtr
165
  parseInternetAddressNoThrow(const std::string& ip_address, uint16_t port = 0, bool v6only = true);
166
167
  /**
168
   * Parse an internet host address (IPv4 or IPv6) AND port, and create an Instance from it. Throws
169
   * EnvoyException if unable to parse the address. This is needed when a shared pointer is needed
170
   * but only a raw instance is available.
171
   * @param Address::Ip& to be copied to the new instance.
172
   * @return pointer to the Instance.
173
   */
174
  static Address::InstanceConstSharedPtr copyInternetAddressAndPort(const Address::Ip& ip);
175
176
  /**
177
   * Create a new Instance from an internet host address (IPv4 or IPv6) and port.
178
   * @param ip_addr string to be parsed as an internet address and port. Examples:
179
   *        - "1.2.3.4:80"
180
   *        - "[1234:5678::9]:443"
181
   * @param v6only disable IPv4-IPv6 mapping for IPv6 addresses?
182
   * @return pointer to the Instance.
183
   * @throw EnvoyException in case of a malformed IP address.
184
   */
185
  static Address::InstanceConstSharedPtr parseInternetAddressAndPort(const std::string& ip_address,
186
                                                                     bool v6only = true);
187
188
  /**
189
   * Create a new Instance from an internet host address (IPv4 or IPv6) and port.
190
   * @param ip_addr string to be parsed as an internet address and port. Examples:
191
   *        - "1.2.3.4:80"
192
   *        - "[1234:5678::9]:443"
193
   * @param v6only disable IPv4-IPv6 mapping for IPv6 addresses?
194
   * @return pointer to the Instance, or a nullptr in case of a malformed IP address.
195
   */
196
  static Address::InstanceConstSharedPtr
197
  parseInternetAddressAndPortNoThrow(const std::string& ip_address, bool v6only = true);
198
199
  /**
200
   * Get the local address of the first interface address that is of type
201
   * version and is not a loopback address. If no matches are found, return the
202
   * loopback address of type version.
203
   * @param the local address IP version.
204
   * @return the local IP address of the server
205
   */
206
  static Address::InstanceConstSharedPtr getLocalAddress(const Address::IpVersion version);
207
208
  /**
209
   * Determine whether this is a local connection.
210
   * @return bool the address is a local connection.
211
   */
212
  static bool isSameIpOrLoopback(const ConnectionInfoProvider& socket);
213
214
  /**
215
   * Determine whether this is an internal (RFC1918) address.
216
   * @return bool the address is an RFC1918 address.
217
   */
218
  static bool isInternalAddress(const Address::Instance& address);
219
220
  /**
221
   * Check if address is loopback address.
222
   * @param address IP address to check.
223
   * @return true if so, otherwise false
224
   */
225
  static bool isLoopbackAddress(const Address::Instance& address);
226
227
  /**
228
   * @return Address::InstanceConstSharedPtr an address that represents the canonical IPv4 loopback
229
   *         address (i.e. "127.0.0.1"). Note that the range "127.0.0.0/8" is all defined as the
230
   *         loopback range, but the address typically used (e.g. in tests) is "127.0.0.1".
231
   */
232
  static Address::InstanceConstSharedPtr getCanonicalIpv4LoopbackAddress();
233
234
  /**
235
   * @return Address::InstanceConstSharedPtr an address that represents the IPv6 loopback address
236
   *         (i.e. "::1").
237
   */
238
  static Address::InstanceConstSharedPtr getIpv6LoopbackAddress();
239
240
  /**
241
   * @return Address::InstanceConstSharedPtr an address that represents the IPv4 wildcard address
242
   *         (i.e. "0.0.0.0"). Used during binding to indicate that incoming connections to any
243
   *         local IPv4 address are to be accepted.
244
   */
245
  static Address::InstanceConstSharedPtr getIpv4AnyAddress();
246
247
  /**
248
   * @return Address::InstanceConstSharedPtr an address that represents the IPv6 wildcard address
249
   *         (i.e. "::"). Used during binding to indicate that incoming connections to any local
250
   *         IPv6 address are to be accepted.
251
   */
252
  static Address::InstanceConstSharedPtr getIpv6AnyAddress();
253
254
  /**
255
   * @return the IPv4 CIDR catch-all address (0.0.0.0/0).
256
   */
257
  static const std::string& getIpv4CidrCatchAllAddress();
258
259
  /**
260
   * @return the IPv6 CIDR catch-all address (::/0).
261
   */
262
  static const std::string& getIpv6CidrCatchAllAddress();
263
264
  /**
265
   * @param address IP address instance.
266
   * @param port to update.
267
   * @return Address::InstanceConstSharedPtr a new address instance with updated port.
268
   */
269
  static Address::InstanceConstSharedPtr getAddressWithPort(const Address::Instance& address,
270
                                                            uint32_t port);
271
272
  /**
273
   * Retrieve the original destination address from an accepted socket.
274
   * The address (IP and port) may be not local and the port may differ from
275
   * the listener port if the packets were redirected using iptables
276
   * @param sock is accepted socket
277
   * @return the original destination or nullptr if not available.
278
   */
279
  static Address::InstanceConstSharedPtr getOriginalDst(Socket& sock);
280
281
  /**
282
   * Parses a string containing a comma-separated list of port numbers and/or
283
   * port ranges and appends the values to a caller-provided list of PortRange structures.
284
   * For example, the string "1-1024,2048-4096,12345" causes 3 PortRange structures
285
   * to be appended to the supplied list.
286
   * @param str is the string containing the port numbers and ranges
287
   * @param list is the list to append the new data structures to
288
   */
289
  static void parsePortRangeList(absl::string_view string, std::list<PortRange>& list);
290
291
  /**
292
   * Checks whether a given port number appears in at least one of the port ranges in a list
293
   * @param address supplies the IP address to compare.
294
   * @param list the list of port ranges in which the port may appear
295
   * @return whether the port appears in at least one of the ranges in the list
296
   */
297
  static bool portInRangeList(const Address::Instance& address, const std::list<PortRange>& list);
298
299
  /**
300
   * Converts IPv6 absl::uint128 in network byte order to host byte order.
301
   * @param address supplies the IPv6 address in network byte order.
302
   * @return the absl::uint128 IPv6 address in host byte order.
303
   */
304
  static absl::uint128 Ip6ntohl(const absl::uint128& address);
305
306
  /**
307
   * Converts IPv6 absl::uint128 in host byte order to network byte order.
308
   * @param address supplies the IPv6 address in host byte order.
309
   * @return the absl::uint128 IPv6 address in network byte order.
310
   */
311
  static absl::uint128 Ip6htonl(const absl::uint128& address);
312
313
  static Address::InstanceConstSharedPtr
314
  protobufAddressToAddress(const envoy::config::core::v3::Address& proto_address);
315
316
  /**
317
   * Copies the address instance into the protobuf representation of an address.
318
   * @param address is the address to be copied into the protobuf representation of this address.
319
   * @param proto_address is the protobuf address to which the address instance is copied into.
320
   */
321
  static void addressToProtobufAddress(const Address::Instance& address,
322
                                       envoy::config::core::v3::Address& proto_address);
323
324
  /**
325
   * Returns socket type corresponding to SocketAddress.protocol value of the
326
   * given address, or SocketType::Stream if the address is a pipe address.
327
   * @param proto_address the address protobuf
328
   * @return socket type
329
   */
330
  static Socket::Type
331
  protobufAddressSocketType(const envoy::config::core::v3::Address& proto_address);
332
333
  /**
334
   * Send a packet via given UDP socket with specific source address.
335
   * @param handle is the UDP socket used to send.
336
   * @param slices points to the buffers containing the packet.
337
   * @param num_slices is the number of buffers.
338
   * @param local_ip is the source address to be used to send.
339
   * @param peer_address is the destination address to send to.
340
   */
341
  static Api::IoCallUint64Result writeToSocket(IoHandle& handle, Buffer::RawSlice* slices,
342
                                               uint64_t num_slices, const Address::Ip* local_ip,
343
                                               const Address::Instance& peer_address);
344
  static Api::IoCallUint64Result writeToSocket(IoHandle& handle, const Buffer::Instance& buffer,
345
                                               const Address::Ip* local_ip,
346
                                               const Address::Instance& peer_address);
347
348
  /**
349
   * Read a packet from a given UDP socket and pass the packet to given UdpPacketProcessor.
350
   * @param handle is the UDP socket to read from.
351
   * @param local_address is the socket's local address used to populate port.
352
   * @param udp_packet_processor is the callback to receive the packet.
353
   * @param receive_time is the timestamp passed to udp_packet_processor for the
354
   * receive time of the packet.
355
   * @param prefer_gro supplies whether to use GRO if the OS supports it.
356
   * @param packets_dropped is the output parameter for number of packets dropped in kernel. If the
357
   * caller is not interested in it, nullptr can be passed in.
358
   */
359
  static Api::IoCallUint64Result readFromSocket(IoHandle& handle,
360
                                                const Address::Instance& local_address,
361
                                                UdpPacketProcessor& udp_packet_processor,
362
                                                MonotonicTime receive_time, bool use_gro,
363
                                                uint32_t* packets_dropped);
364
365
  /**
366
   * Read some packets from a given UDP socket and pass the packet to a given
367
   * UdpPacketProcessor. Read no more than MAX_NUM_PACKETS_PER_EVENT_LOOP packets.
368
   * @param handle is the UDP socket to read from.
369
   * @param local_address is the socket's local address used to populate port.
370
   * @param udp_packet_processor is the callback to receive the packets.
371
   * @param time_source is the time source used to generate the time stamp of the received packets.
372
   * @param prefer_gro supplies whether to use GRO if the OS supports it.
373
   * @param packets_dropped is the output parameter for number of packets dropped in kernel.
374
   * Return the io error encountered or nullptr if no io error but read stopped
375
   * because of MAX_NUM_PACKETS_PER_EVENT_LOOP.
376
   *
377
   * TODO(mattklein123): Allow the number of packets read to be limited for fairness. Currently
378
   *                     this function will always return an error, even if EAGAIN. In the future
379
   *                     we can return no error if we limited the number of packets read and have
380
   *                     to fake another read event.
381
   * TODO(mattklein123): Can we potentially share this with the TCP stack somehow? Similar code
382
   *                     exists there.
383
   */
384
  static Api::IoErrorPtr readPacketsFromSocket(IoHandle& handle,
385
                                               const Address::Instance& local_address,
386
                                               UdpPacketProcessor& udp_packet_processor,
387
                                               TimeSource& time_source, bool prefer_gro,
388
                                               uint32_t& packets_dropped);
389
390
private:
391
  static void throwWithMalformedIp(absl::string_view ip_address);
392
393
  /**
394
   * Takes a number and flips the order in byte chunks. The last byte of the input will be the
395
   * first byte in the output. The second to last byte will be the second to first byte in the
396
   * output. Etc..
397
   * @param input supplies the input to have the bytes flipped.
398
   * @return the absl::uint128 of the input having the bytes flipped.
399
   */
400
  static absl::uint128 flipOrder(const absl::uint128& input);
401
};
402
403
/**
404
 * Log formatter for an address.
405
 */
406
struct AddressStrFormatter {
407
515
  void operator()(std::string* out, const Network::Address::InstanceConstSharedPtr& instance) {
408
515
    out->append(instance->asString());
409
515
  }
410
};
411
412
} // namespace Network
413
} // namespace Envoy