Line data Source code
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 3390 : 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 91 : 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 8 : void operator()(std::string* out, const Network::Address::InstanceConstSharedPtr& instance) { 408 8 : out->append(instance->asString()); 409 8 : } 410 : }; 411 : 412 : } // namespace Network 413 : } // namespace Envoy