Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Luke Huang | 2559932 | 2019-06-14 00:34:05 +0800 | [diff] [blame] | 17 | #pragma once |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 18 | |
Luke Huang | 2559932 | 2019-06-14 00:34:05 +0800 | [diff] [blame] | 19 | #include <netdb.h> |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 20 | #include <netinet/in.h> |
| 21 | #include <stdint.h> |
| 22 | #include <cstring> |
| 23 | #include <limits> |
| 24 | #include <string> |
| 25 | |
| 26 | #include "netdutils/NetworkConstants.h" |
| 27 | |
| 28 | namespace android { |
| 29 | namespace netdutils { |
| 30 | |
| 31 | namespace internal_ { |
| 32 | |
| 33 | // A structure to hold data for dealing with Internet addresses (IPAddress) and |
| 34 | // related types such as IPSockAddr and IPPrefix. |
| 35 | struct compact_ipdata { |
| 36 | uint8_t family{AF_UNSPEC}; |
Erik Kline | 603df20 | 2018-09-10 18:16:26 +0900 | [diff] [blame] | 37 | uint8_t cidrlen{0U}; // written and read in host-byte order |
| 38 | in_port_t port{0U}; // written and read in host-byte order |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 39 | uint32_t scope_id{0U}; |
| 40 | union { |
| 41 | in_addr v4; |
| 42 | in6_addr v6; |
Erik Kline | 603df20 | 2018-09-10 18:16:26 +0900 | [diff] [blame] | 43 | } ip{.v6 = IN6ADDR_ANY_INIT}; // written and read in network-byte order |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 44 | |
| 45 | // Classes that use compact_ipdata and this method should be sure to clear |
| 46 | // (i.e. zero or make uniform) any fields not relevant to the class. |
| 47 | friend bool operator==(const compact_ipdata& a, const compact_ipdata& b) { |
| 48 | if ((a.family != b.family) || (a.cidrlen != b.cidrlen) || (a.port != b.port) || |
| 49 | (a.scope_id != b.scope_id)) { |
| 50 | return false; |
| 51 | } |
| 52 | switch (a.family) { |
Erik Kline | 603df20 | 2018-09-10 18:16:26 +0900 | [diff] [blame] | 53 | case AF_UNSPEC: |
| 54 | // After the above checks, two AF_UNSPEC objects can be |
| 55 | // considered equal, for convenience. |
| 56 | return true; |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 57 | case AF_INET: { |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 58 | const in_addr v4a = a.ip.v4; |
| 59 | const in_addr v4b = b.ip.v4; |
Erik Kline | 603df20 | 2018-09-10 18:16:26 +0900 | [diff] [blame] | 60 | return (v4a.s_addr == v4b.s_addr); |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 61 | } |
| 62 | case AF_INET6: { |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 63 | const in6_addr v6a = a.ip.v6; |
| 64 | const in6_addr v6b = b.ip.v6; |
Erik Kline | 603df20 | 2018-09-10 18:16:26 +0900 | [diff] [blame] | 65 | return IN6_ARE_ADDR_EQUAL(&v6a, &v6b); |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 66 | } |
| 67 | } |
Erik Kline | 603df20 | 2018-09-10 18:16:26 +0900 | [diff] [blame] | 68 | return false; |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | // Classes that use compact_ipdata and this method should be sure to clear |
| 72 | // (i.e. zero or make uniform) any fields not relevant to the class. |
| 73 | friend bool operator!=(const compact_ipdata& a, const compact_ipdata& b) { return !(a == b); } |
| 74 | |
| 75 | // Classes that use compact_ipdata and this method should be sure to clear |
| 76 | // (i.e. zero or make uniform) any fields not relevant to the class. |
| 77 | friend bool operator<(const compact_ipdata& a, const compact_ipdata& b) { |
| 78 | if (a.family != b.family) return (a.family < b.family); |
| 79 | switch (a.family) { |
| 80 | case AF_INET: { |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 81 | const in_addr v4a = a.ip.v4; |
| 82 | const in_addr v4b = b.ip.v4; |
| 83 | if (v4a.s_addr != v4b.s_addr) return (ntohl(v4a.s_addr) < ntohl(v4b.s_addr)); |
| 84 | break; |
| 85 | } |
| 86 | case AF_INET6: { |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 87 | const in6_addr v6a = a.ip.v6; |
| 88 | const in6_addr v6b = b.ip.v6; |
Erik Kline | 603df20 | 2018-09-10 18:16:26 +0900 | [diff] [blame] | 89 | const int cmp = std::memcmp(v6a.s6_addr, v6b.s6_addr, IPV6_ADDR_LEN); |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 90 | if (cmp != 0) return cmp < 0; |
| 91 | break; |
| 92 | } |
| 93 | } |
| 94 | if (a.cidrlen != b.cidrlen) return (a.cidrlen < b.cidrlen); |
| 95 | if (a.port != b.port) return (a.port < b.port); |
| 96 | return (a.scope_id < b.scope_id); |
| 97 | } |
| 98 | }; |
| 99 | |
| 100 | static_assert(AF_UNSPEC <= std::numeric_limits<uint8_t>::max(), "AF_UNSPEC value too large"); |
| 101 | static_assert(AF_INET <= std::numeric_limits<uint8_t>::max(), "AF_INET value too large"); |
| 102 | static_assert(AF_INET6 <= std::numeric_limits<uint8_t>::max(), "AF_INET6 value too large"); |
| 103 | static_assert(sizeof(compact_ipdata) == 24U, "compact_ipdata unexpectedly large"); |
| 104 | |
| 105 | } // namespace internal_ |
| 106 | |
Luke Huang | 2559932 | 2019-06-14 00:34:05 +0800 | [diff] [blame] | 107 | struct AddrinfoDeleter { |
| 108 | void operator()(struct addrinfo* p) const { |
| 109 | if (p != nullptr) { |
| 110 | freeaddrinfo(p); |
| 111 | } |
| 112 | } |
| 113 | }; |
| 114 | |
| 115 | typedef std::unique_ptr<struct addrinfo, struct AddrinfoDeleter> ScopedAddrinfo; |
| 116 | |
Erik Kline | 603df20 | 2018-09-10 18:16:26 +0900 | [diff] [blame] | 117 | inline bool usesScopedIds(const in6_addr& ipv6) { |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 118 | return (IN6_IS_ADDR_LINKLOCAL(&ipv6) || IN6_IS_ADDR_MC_LINKLOCAL(&ipv6)); |
| 119 | } |
| 120 | |
| 121 | class IPPrefix; |
| 122 | class IPSockAddr; |
| 123 | |
| 124 | class IPAddress { |
| 125 | public: |
| 126 | static bool forString(const std::string& repr, IPAddress* ip); |
| 127 | static IPAddress forString(const std::string& repr) { |
| 128 | IPAddress ip; |
| 129 | if (!forString(repr, &ip)) return IPAddress(); |
| 130 | return ip; |
| 131 | } |
| 132 | |
| 133 | IPAddress() = default; |
| 134 | IPAddress(const IPAddress&) = default; |
| 135 | IPAddress(IPAddress&&) = default; |
| 136 | |
| 137 | explicit IPAddress(const in_addr& ipv4) |
| 138 | : mData({AF_INET, IPV4_ADDR_BITS, 0U, 0U, {.v4 = ipv4}}) {} |
| 139 | explicit IPAddress(const in6_addr& ipv6) |
| 140 | : mData({AF_INET6, IPV6_ADDR_BITS, 0U, 0U, {.v6 = ipv6}}) {} |
| 141 | IPAddress(const in6_addr& ipv6, uint32_t scope_id) |
| 142 | : mData({AF_INET6, |
| 143 | IPV6_ADDR_BITS, |
| 144 | 0U, |
| 145 | // Sanity check: scoped_ids only for link-local addresses. |
Erik Kline | 603df20 | 2018-09-10 18:16:26 +0900 | [diff] [blame] | 146 | usesScopedIds(ipv6) ? scope_id : 0U, |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 147 | {.v6 = ipv6}}) {} |
| 148 | IPAddress(const IPAddress& ip, uint32_t scope_id) : IPAddress(ip) { |
Erik Kline | 603df20 | 2018-09-10 18:16:26 +0900 | [diff] [blame] | 149 | mData.scope_id = (family() == AF_INET6 && usesScopedIds(mData.ip.v6)) ? scope_id : 0U; |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 150 | } |
| 151 | |
| 152 | IPAddress& operator=(const IPAddress&) = default; |
| 153 | IPAddress& operator=(IPAddress&&) = default; |
| 154 | |
| 155 | constexpr sa_family_t family() const noexcept { return mData.family; } |
| 156 | constexpr uint32_t scope_id() const noexcept { return mData.scope_id; } |
| 157 | |
| 158 | std::string toString() const noexcept; |
| 159 | |
| 160 | friend std::ostream& operator<<(std::ostream& os, const IPAddress& ip) { |
| 161 | os << ip.toString(); |
| 162 | return os; |
| 163 | } |
| 164 | friend bool operator==(const IPAddress& a, const IPAddress& b) { return (a.mData == b.mData); } |
| 165 | friend bool operator!=(const IPAddress& a, const IPAddress& b) { return (a.mData != b.mData); } |
| 166 | friend bool operator<(const IPAddress& a, const IPAddress& b) { return (a.mData < b.mData); } |
| 167 | friend bool operator>(const IPAddress& a, const IPAddress& b) { return (b.mData < a.mData); } |
| 168 | friend bool operator<=(const IPAddress& a, const IPAddress& b) { return (a < b) || (a == b); } |
| 169 | friend bool operator>=(const IPAddress& a, const IPAddress& b) { return (b < a) || (a == b); } |
| 170 | |
| 171 | private: |
| 172 | friend class IPPrefix; |
| 173 | friend class IPSockAddr; |
| 174 | |
| 175 | explicit IPAddress(const internal_::compact_ipdata& ipdata) : mData(ipdata) { |
| 176 | mData.port = 0U; |
| 177 | switch (mData.family) { |
| 178 | case AF_INET: |
| 179 | mData.cidrlen = IPV4_ADDR_BITS; |
| 180 | mData.scope_id = 0U; |
| 181 | break; |
| 182 | case AF_INET6: |
| 183 | mData.cidrlen = IPV6_ADDR_BITS; |
Erik Kline | 603df20 | 2018-09-10 18:16:26 +0900 | [diff] [blame] | 184 | if (usesScopedIds(ipdata.ip.v6)) mData.scope_id = ipdata.scope_id; |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 185 | break; |
| 186 | default: |
| 187 | mData.cidrlen = 0U; |
| 188 | mData.scope_id = 0U; |
| 189 | break; |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | internal_::compact_ipdata mData{}; |
| 194 | }; |
| 195 | |
| 196 | class IPPrefix { |
| 197 | public: |
Lorenzo Colitti | 11fa41d | 2020-05-19 08:12:55 +0000 | [diff] [blame] | 198 | static bool forString(const std::string& repr, IPPrefix* prefix); |
| 199 | static IPPrefix forString(const std::string& repr) { |
| 200 | IPPrefix prefix; |
| 201 | if (!forString(repr, &prefix)) return IPPrefix(); |
| 202 | return prefix; |
| 203 | } |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 204 | |
| 205 | IPPrefix() = default; |
| 206 | IPPrefix(const IPPrefix&) = default; |
| 207 | IPPrefix(IPPrefix&&) = default; |
| 208 | |
| 209 | explicit IPPrefix(const IPAddress& ip) : mData(ip.mData) {} |
| 210 | |
| 211 | // Truncate the IP address |ip| at length |length|. Lengths greater than |
| 212 | // the address-family-relevant maximum, along with negative values, are |
| 213 | // interpreted as if the address-family-relevant maximum had been given. |
| 214 | IPPrefix(const IPAddress& ip, int length); |
| 215 | |
| 216 | IPPrefix& operator=(const IPPrefix&) = default; |
| 217 | IPPrefix& operator=(IPPrefix&&) = default; |
| 218 | |
| 219 | constexpr sa_family_t family() const noexcept { return mData.family; } |
| 220 | IPAddress ip() const noexcept { return IPAddress(mData); } |
Mike Yu | 0ae31af | 2018-11-15 21:58:19 +0800 | [diff] [blame] | 221 | in_addr addr4() const noexcept { return mData.ip.v4; } |
| 222 | in6_addr addr6() const noexcept { return mData.ip.v6; } |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 223 | constexpr int length() const noexcept { return mData.cidrlen; } |
| 224 | |
nuccachen | f52f7a5 | 2018-07-17 18:07:23 +0800 | [diff] [blame] | 225 | bool isUninitialized() const noexcept; |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 226 | std::string toString() const noexcept; |
| 227 | |
| 228 | friend std::ostream& operator<<(std::ostream& os, const IPPrefix& prefix) { |
| 229 | os << prefix.toString(); |
| 230 | return os; |
| 231 | } |
| 232 | friend bool operator==(const IPPrefix& a, const IPPrefix& b) { return (a.mData == b.mData); } |
| 233 | friend bool operator!=(const IPPrefix& a, const IPPrefix& b) { return (a.mData != b.mData); } |
| 234 | friend bool operator<(const IPPrefix& a, const IPPrefix& b) { return (a.mData < b.mData); } |
| 235 | friend bool operator>(const IPPrefix& a, const IPPrefix& b) { return (b.mData < a.mData); } |
| 236 | friend bool operator<=(const IPPrefix& a, const IPPrefix& b) { return (a < b) || (a == b); } |
| 237 | friend bool operator>=(const IPPrefix& a, const IPPrefix& b) { return (b < a) || (a == b); } |
| 238 | |
| 239 | private: |
| 240 | internal_::compact_ipdata mData{}; |
| 241 | }; |
| 242 | |
| 243 | // An Internet socket address. |
| 244 | // |
| 245 | // Cannot represent other types of socket addresses (e.g. UNIX socket address, et cetera). |
| 246 | class IPSockAddr { |
| 247 | public: |
| 248 | // TODO: static forString |
| 249 | |
Mike Yu | 2f35dc8 | 2019-10-16 17:22:37 +0800 | [diff] [blame] | 250 | static IPSockAddr toIPSockAddr(const std::string& repr, in_port_t port) { |
| 251 | return IPSockAddr(IPAddress::forString(repr), port); |
| 252 | } |
| 253 | static IPSockAddr toIPSockAddr(const sockaddr& sa) { |
| 254 | switch (sa.sa_family) { |
| 255 | case AF_INET: |
| 256 | return IPSockAddr(*reinterpret_cast<const sockaddr_in*>(&sa)); |
| 257 | case AF_INET6: |
| 258 | return IPSockAddr(*reinterpret_cast<const sockaddr_in6*>(&sa)); |
| 259 | default: |
| 260 | return IPSockAddr(); |
| 261 | } |
| 262 | } |
| 263 | static IPSockAddr toIPSockAddr(const sockaddr_storage& ss) { |
| 264 | return toIPSockAddr(*reinterpret_cast<const sockaddr*>(&ss)); |
| 265 | } |
| 266 | |
Erik Kline | d26a2c2 | 2018-05-11 19:33:19 +0900 | [diff] [blame] | 267 | IPSockAddr() = default; |
| 268 | IPSockAddr(const IPSockAddr&) = default; |
| 269 | IPSockAddr(IPSockAddr&&) = default; |
| 270 | |
| 271 | explicit IPSockAddr(const IPAddress& ip) : mData(ip.mData) {} |
| 272 | IPSockAddr(const IPAddress& ip, in_port_t port) : mData(ip.mData) { mData.port = port; } |
| 273 | explicit IPSockAddr(const sockaddr_in& ipv4sa) |
| 274 | : IPSockAddr(IPAddress(ipv4sa.sin_addr), ntohs(ipv4sa.sin_port)) {} |
| 275 | explicit IPSockAddr(const sockaddr_in6& ipv6sa) |
| 276 | : IPSockAddr(IPAddress(ipv6sa.sin6_addr, ipv6sa.sin6_scope_id), ntohs(ipv6sa.sin6_port)) {} |
| 277 | |
| 278 | IPSockAddr& operator=(const IPSockAddr&) = default; |
| 279 | IPSockAddr& operator=(IPSockAddr&&) = default; |
| 280 | |
| 281 | constexpr sa_family_t family() const noexcept { return mData.family; } |
| 282 | IPAddress ip() const noexcept { return IPAddress(mData); } |
| 283 | constexpr in_port_t port() const noexcept { return mData.port; } |
| 284 | |
| 285 | // Implicit conversion to sockaddr_storage. |
| 286 | operator sockaddr_storage() const noexcept { |
| 287 | sockaddr_storage ss; |
| 288 | ss.ss_family = mData.family; |
| 289 | switch (mData.family) { |
| 290 | case AF_INET: |
| 291 | reinterpret_cast<sockaddr_in*>(&ss)->sin_addr = mData.ip.v4; |
| 292 | reinterpret_cast<sockaddr_in*>(&ss)->sin_port = htons(mData.port); |
| 293 | break; |
| 294 | case AF_INET6: |
| 295 | reinterpret_cast<sockaddr_in6*>(&ss)->sin6_addr = mData.ip.v6; |
| 296 | reinterpret_cast<sockaddr_in6*>(&ss)->sin6_port = htons(mData.port); |
| 297 | reinterpret_cast<sockaddr_in6*>(&ss)->sin6_scope_id = mData.scope_id; |
| 298 | break; |
| 299 | } |
| 300 | return ss; |
| 301 | } |
| 302 | |
| 303 | std::string toString() const noexcept; |
| 304 | |
| 305 | friend std::ostream& operator<<(std::ostream& os, const IPSockAddr& prefix) { |
| 306 | os << prefix.toString(); |
| 307 | return os; |
| 308 | } |
| 309 | friend bool operator==(const IPSockAddr& a, const IPSockAddr& b) { |
| 310 | return (a.mData == b.mData); |
| 311 | } |
| 312 | friend bool operator!=(const IPSockAddr& a, const IPSockAddr& b) { |
| 313 | return (a.mData != b.mData); |
| 314 | } |
| 315 | friend bool operator<(const IPSockAddr& a, const IPSockAddr& b) { return (a.mData < b.mData); } |
| 316 | friend bool operator>(const IPSockAddr& a, const IPSockAddr& b) { return (b.mData < a.mData); } |
| 317 | friend bool operator<=(const IPSockAddr& a, const IPSockAddr& b) { return (a < b) || (a == b); } |
| 318 | friend bool operator>=(const IPSockAddr& a, const IPSockAddr& b) { return (b < a) || (a == b); } |
| 319 | |
| 320 | private: |
| 321 | internal_::compact_ipdata mData{}; |
| 322 | }; |
| 323 | |
| 324 | } // namespace netdutils |
| 325 | } // namespace android |