| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SERVICES_NETWORK_PUBLIC_CPP_IP_ADDRESS_SPACE_UTIL_H_ |
| #define SERVICES_NETWORK_PUBLIC_CPP_IP_ADDRESS_SPACE_UTIL_H_ |
| |
| #include <optional> |
| #include <string_view> |
| #include <vector> |
| |
| #include "base/component_export.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/stack_allocated.h" |
| #include "base/no_destructor.h" |
| #include "base/synchronization/lock.h" |
| #include "net/base/ip_address.h" |
| #include "net/base/ip_endpoint.h" |
| #include "services/network/public/mojom/ip_address_space.mojom-forward.h" |
| #include "services/network/public/mojom/parsed_headers.mojom-forward.h" |
| #include "services/network/public/mojom/url_loader_network_service_observer.mojom-forward.h" |
| |
| class GURL; |
| |
| namespace net { |
| |
| struct TransportInfo; |
| |
| } // namespace net |
| |
| namespace network { |
| |
| // Returns a human-readable string representing `result`, suitable for logging. |
| std::string_view COMPONENT_EXPORT(NETWORK_CPP) |
| LocalNetworkAccessResultToStringPiece( |
| mojom::LocalNetworkAccessResult result); |
| |
| // Returns a human-readable string representing `transport_type`, suitable for |
| // logging. |
| std::string_view COMPONENT_EXPORT(NETWORK_CPP) |
| TransportTypeToStringPiece(mojom::TransportType transport_type); |
| |
| // Returns a human-readable string representing `space`, suitable for logging. |
| std::string_view COMPONENT_EXPORT(NETWORK_CPP) |
| IPAddressSpaceToStringPiece(mojom::IPAddressSpace space); |
| |
| // Returns the `IPAddressSpace` to which `address` belongs. |
| // Returns `kUnknown` for invalid IP addresses. |
| // |
| // WARNING: Most callers will want to use `TransportInfoToIPAddressSpace()` |
| // below instead, as this does not properly account for proxies nor for |
| // command-line overrides. |
| mojom::IPAddressSpace COMPONENT_EXPORT(NETWORK_CPP) |
| IPAddressToIPAddressSpace(const net::IPAddress& address); |
| |
| // Returns the `IPAddressSpace` to which `endpoint` belongs. |
| // Returns `kUnknown` for invalid IP addresses. |
| // |
| // WARNING: Most callers will want to use `TransportInfoToIPAddressSpace()` |
| // below instead, as this does not properly account for proxies. It does account |
| // for command-line overrides though. |
| mojom::IPAddressSpace COMPONENT_EXPORT(NETWORK_CPP) |
| IPEndPointToIPAddressSpace(const net::IPEndPoint& endpoint); |
| |
| // Returns the `IPAddressSpace` to which the endpoint of `transport` belongs. |
| // |
| // When the transport is a proxied connection, returns `kUnknown`. See |
| // https://github.com/WICG/private-network-access/issues/62 for more details on |
| // the reasoning there. |
| // |
| // When the transport is a direct connection, returns the IP address space of |
| // `info.endpoint`. This returns `kUnknown` for invalid IP addresses. Otherwise, |
| // takes into account the `--ip-address-space-overrides` command-line switch. If |
| // no override applies, then follows this algorithm: |
| // https://wicg.github.io/local-network-access/#determine-the-ip-address-space |
| // |
| // `info.endpoint`'s port is only used for matching to command-line overrides. |
| // It is ignored otherwise. In particular, if no overrides are specified on the |
| // command-line, then this function ignores the port entirely. |
| // |
| // WARNING: This can only be used as-is for subresource requests loaded over the |
| // network. Special URL schemes and resource headers must also be taken into |
| // account at higher layers. |
| mojom::IPAddressSpace COMPONENT_EXPORT(NETWORK_CPP) |
| TransportInfoToIPAddressSpace(const net::TransportInfo& info); |
| |
| // Returns whether `lhs` is less public than `rhs`. |
| // |
| // This comparator is compatible with std::less. |
| // |
| // Address spaces go from most public to least public in the following order: |
| // |
| // - public and unknown (equivalent) |
| // - local |
| // - loopback |
| // |
| bool COMPONENT_EXPORT(NETWORK_CPP) |
| IsLessPublicAddressSpace(mojom::IPAddressSpace lhs, |
| mojom::IPAddressSpace rhs); |
| |
| // Returns whether `lhs` is less public than `rhs`, but collapses the local |
| // and loopback address spaces into the same bucket. |
| // |
| // This comparator is compatible with std::less. |
| // |
| // Address spaces go from most public to least public in the following order: |
| // |
| // - public and unknown (equivalent) |
| // - local and loopback (equivalent) |
| // |
| bool COMPONENT_EXPORT(NETWORK_CPP) |
| IsLessPublicAddressSpaceLNA(mojom::IPAddressSpace lhs, |
| mojom::IPAddressSpace rhs); |
| |
| // Represents optional parameters of CalculateClientAddressSpace(). |
| // This is effectively a subset of network::mojom::URLResponseHead. |
| // WARNING: This struct just keeps references to parameters and does not own |
| // them nor make copy of them. Parameters must outlive this struct. For example, |
| // passing net::IPEndPoint() as `remote_endpoint` is invalid. |
| struct COMPONENT_EXPORT(NETWORK_CPP) CalculateClientAddressSpaceParams { |
| STACK_ALLOCATED(); |
| |
| public: |
| ~CalculateClientAddressSpaceParams(); |
| |
| const std::optional<mojom::IPAddressSpace> |
| client_address_space_inherited_from_service_worker; |
| const raw_ptr<const mojom::ParsedHeadersPtr> parsed_headers; |
| const raw_ptr<const net::IPEndPoint> remote_endpoint; |
| }; |
| |
| // Given a request URL and `params`, this function calculates the |
| // IPAddressSpace which should be associated with documents or worker global |
| // scopes (collectively: request clients) instantiated from this resource. |
| // |
| // `params` is optional. If `params` contain values, values must be valid and |
| // `params.value().parsed_headers` must be populated with the result of |
| // parsing the corresponding response headers. |
| // |
| // WARNING: This function is defined here for proximity with related code and |
| // the data structures involved. However since it deals with higher-level |
| // concepts too (documents and worker global scopes), it should probably only be |
| // used at the content/ layer or above. |
| // |
| // See: https://wicg.github.io/cors-rfc1918/#address-space |
| mojom::IPAddressSpace COMPONENT_EXPORT(NETWORK_CPP) CalculateClientAddressSpace( |
| const GURL& url, |
| std::optional<CalculateClientAddressSpaceParams> params); |
| |
| // Given a response URL and the IP endpoint the requested resource was fetched |
| // from, this function calculates the IPAddressSpace of the requested resource. |
| // |
| // As opposed to CalculateClientAddressSpace(), this function is used to |
| // determine the address space of the *target* of a fetch, for comparison with |
| // that of the client of the fetch. |
| // |
| // See: https://wicg.github.io/cors-rfc1918/#integration-fetch |
| mojom::IPAddressSpace COMPONENT_EXPORT(NETWORK_CPP) |
| CalculateResourceAddressSpace(const GURL& url, |
| const net::IPEndPoint& endpoint); |
| |
| // Return the IP address of the host if the host is a private IP address |
| // literal, otherwise returns std::nullopt. |
| // |
| // This does not apply any IP address space overrides. |
| std::optional<net::IPAddress> COMPONENT_EXPORT(NETWORK_CPP) |
| ParsePrivateIpFromUrl(const GURL& url); |
| |
| // Return the IP address space of the host if we can determine it from the URL, |
| // otherwise returns std::nullopt. |
| // |
| // Cases in which we can determine the IP address space: |
| // |
| // * host is an IP address literal |
| // * host is a .local domain (e.g. RFC6762), or 'local'/'local.' |
| // * host is 'localhost', 'localhost.' (or a .localhost domain). |
| // |
| // This function will apply IP address space overrides. |
| std::optional<mojom::IPAddressSpace> COMPONENT_EXPORT(NETWORK_CPP) |
| GetAddressSpaceFromUrl(const GURL& url); |
| |
| class COMPONENT_EXPORT(NETWORK_CPP) IPAddressSpaceOverrides { |
| public: |
| static IPAddressSpaceOverrides& GetInstance(); |
| |
| ~IPAddressSpaceOverrides() = delete; |
| IPAddressSpaceOverrides(const IPAddressSpaceOverrides&) = delete; |
| IPAddressSpaceOverrides& operator=(const IPAddressSpaceOverrides&) = delete; |
| |
| struct CIDR { |
| net::IPAddress ip_address; |
| size_t mask_bits; |
| }; |
| |
| // Represents a single command-line-specified override. Exactly one of |
| // endpoint or cidr should be specified. |
| struct AddressSpaceOverride { |
| AddressSpaceOverride(); |
| ~AddressSpaceOverride(); |
| AddressSpaceOverride(const AddressSpaceOverride&); |
| AddressSpaceOverride& operator=(const AddressSpaceOverride& other); |
| AddressSpaceOverride(AddressSpaceOverride&&); |
| AddressSpaceOverride& operator=(AddressSpaceOverride&& other); |
| |
| // The IP endpoint to override the address space for, if present. |
| std::optional<net::IPEndPoint> endpoint; |
| // The CIDR range to override the address space for, if present. |
| std::optional<CIDR> cidr; |
| |
| // The IP address space to which `endpoint` should be mapped. |
| mojom::IPAddressSpace space; |
| }; |
| |
| // Checks to see if there is an IP Address Space override for the given |
| // endpoint, and if so, returns it. Returns std::nullopt if there is no |
| // override. Overrides are checked in-order (with command-line overrides |
| // being checked first), first override that matches wins. |
| // |
| // This method is safe to be called from any thread. |
| std::optional<mojom::IPAddressSpace> HasOverride( |
| const net::IPEndPoint& endpoint); |
| |
| // Returns the current overrides, combining 1) the |
| // --ip-address-space-overrides command-line parameter, 2) the |
| // argument passed to SetAuxiliaryOverrides (which is generally the value |
| // taken from the enterprise policy). |
| // |
| // This method is safe to be called from any thread. |
| std::vector<std::string> GetCurrentOverrides(); |
| |
| // Allows setting overrides from an additional source (e.g. from an enterprise |
| // policy). |
| // |
| // Overrides will be parsed, and any overrides that fail validation will be |
| // appended to the optional |rejected_overrides| output parameter. |
| // |
| // This method is safe to be called from any thread. |
| void SetAuxiliaryOverrides(const std::string& auxiliary_overrides, |
| std::vector<std::string>* rejected_overrides); |
| |
| // Empties the overrides list. |
| // |
| // This function is safe to be called from any thread. |
| void ResetForTesting(); |
| |
| private: |
| friend class base::NoDestructor<IPAddressSpaceOverrides>; |
| IPAddressSpaceOverrides(); |
| |
| void ParseCmdlineIfNeeded() EXCLUSIVE_LOCKS_REQUIRED(lock_); |
| |
| base::Lock lock_; |
| |
| bool has_cmdline_been_parsed_ GUARDED_BY(lock_) = false; |
| std::vector<std::string> cmdline_overrides_ GUARDED_BY(lock_); |
| std::vector<AddressSpaceOverride> parsed_cmdline_overrides_ GUARDED_BY(lock_); |
| |
| std::vector<std::string> auxiliary_overrides_ GUARDED_BY(lock_); |
| std::vector<AddressSpaceOverride> parsed_auxiliary_overrides_ |
| GUARDED_BY(lock_); |
| }; |
| |
| } // namespace network |
| |
| #endif // SERVICES_NETWORK_PUBLIC_CPP_IP_ADDRESS_SPACE_UTIL_H_ |