Coverage Report

Created: 2024-09-19 09:45

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