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