LCOV - code coverage report
Current view: top level - source/common/network - utility.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 5 6 83.3 %
Date: 2024-01-05 06:35:25 Functions: 3 4 75.0 %

          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

Generated by: LCOV version 1.15