blob: 472ac8946a1141e6ac8cf1071f027357a6c4cd7a [file] [log] [blame]
Erik Klined26a2c22018-05-11 19:33:19 +09001/*
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 Huang25599322019-06-14 00:34:05 +080017#pragma once
Erik Klined26a2c22018-05-11 19:33:19 +090018
Luke Huang25599322019-06-14 00:34:05 +080019#include <netdb.h>
Erik Klined26a2c22018-05-11 19:33:19 +090020#include <netinet/in.h>
21#include <stdint.h>
22#include <cstring>
23#include <limits>
24#include <string>
25
26#include "netdutils/NetworkConstants.h"
27
28namespace android {
29namespace netdutils {
30
31namespace internal_ {
32
33// A structure to hold data for dealing with Internet addresses (IPAddress) and
34// related types such as IPSockAddr and IPPrefix.
35struct compact_ipdata {
36 uint8_t family{AF_UNSPEC};
Erik Kline603df202018-09-10 18:16:26 +090037 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 Klined26a2c22018-05-11 19:33:19 +090039 uint32_t scope_id{0U};
40 union {
41 in_addr v4;
42 in6_addr v6;
Erik Kline603df202018-09-10 18:16:26 +090043 } ip{.v6 = IN6ADDR_ANY_INIT}; // written and read in network-byte order
Erik Klined26a2c22018-05-11 19:33:19 +090044
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 Kline603df202018-09-10 18:16:26 +090053 case AF_UNSPEC:
54 // After the above checks, two AF_UNSPEC objects can be
55 // considered equal, for convenience.
56 return true;
Erik Klined26a2c22018-05-11 19:33:19 +090057 case AF_INET: {
Erik Klined26a2c22018-05-11 19:33:19 +090058 const in_addr v4a = a.ip.v4;
59 const in_addr v4b = b.ip.v4;
Erik Kline603df202018-09-10 18:16:26 +090060 return (v4a.s_addr == v4b.s_addr);
Erik Klined26a2c22018-05-11 19:33:19 +090061 }
62 case AF_INET6: {
Erik Klined26a2c22018-05-11 19:33:19 +090063 const in6_addr v6a = a.ip.v6;
64 const in6_addr v6b = b.ip.v6;
Erik Kline603df202018-09-10 18:16:26 +090065 return IN6_ARE_ADDR_EQUAL(&v6a, &v6b);
Erik Klined26a2c22018-05-11 19:33:19 +090066 }
67 }
Erik Kline603df202018-09-10 18:16:26 +090068 return false;
Erik Klined26a2c22018-05-11 19:33:19 +090069 }
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 Klined26a2c22018-05-11 19:33:19 +090081 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 Klined26a2c22018-05-11 19:33:19 +090087 const in6_addr v6a = a.ip.v6;
88 const in6_addr v6b = b.ip.v6;
Erik Kline603df202018-09-10 18:16:26 +090089 const int cmp = std::memcmp(v6a.s6_addr, v6b.s6_addr, IPV6_ADDR_LEN);
Erik Klined26a2c22018-05-11 19:33:19 +090090 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
100static_assert(AF_UNSPEC <= std::numeric_limits<uint8_t>::max(), "AF_UNSPEC value too large");
101static_assert(AF_INET <= std::numeric_limits<uint8_t>::max(), "AF_INET value too large");
102static_assert(AF_INET6 <= std::numeric_limits<uint8_t>::max(), "AF_INET6 value too large");
103static_assert(sizeof(compact_ipdata) == 24U, "compact_ipdata unexpectedly large");
104
105} // namespace internal_
106
Luke Huang25599322019-06-14 00:34:05 +0800107struct AddrinfoDeleter {
108 void operator()(struct addrinfo* p) const {
109 if (p != nullptr) {
110 freeaddrinfo(p);
111 }
112 }
113};
114
115typedef std::unique_ptr<struct addrinfo, struct AddrinfoDeleter> ScopedAddrinfo;
116
Erik Kline603df202018-09-10 18:16:26 +0900117inline bool usesScopedIds(const in6_addr& ipv6) {
Erik Klined26a2c22018-05-11 19:33:19 +0900118 return (IN6_IS_ADDR_LINKLOCAL(&ipv6) || IN6_IS_ADDR_MC_LINKLOCAL(&ipv6));
119}
120
121class IPPrefix;
122class IPSockAddr;
123
124class 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 Kline603df202018-09-10 18:16:26 +0900146 usesScopedIds(ipv6) ? scope_id : 0U,
Erik Klined26a2c22018-05-11 19:33:19 +0900147 {.v6 = ipv6}}) {}
148 IPAddress(const IPAddress& ip, uint32_t scope_id) : IPAddress(ip) {
Erik Kline603df202018-09-10 18:16:26 +0900149 mData.scope_id = (family() == AF_INET6 && usesScopedIds(mData.ip.v6)) ? scope_id : 0U;
Erik Klined26a2c22018-05-11 19:33:19 +0900150 }
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 Kline603df202018-09-10 18:16:26 +0900184 if (usesScopedIds(ipdata.ip.v6)) mData.scope_id = ipdata.scope_id;
Erik Klined26a2c22018-05-11 19:33:19 +0900185 break;
186 default:
187 mData.cidrlen = 0U;
188 mData.scope_id = 0U;
189 break;
190 }
191 }
192
193 internal_::compact_ipdata mData{};
194};
195
196class IPPrefix {
197 public:
198 // TODO: "static forString(...)" using NetdConstants' parsePrefix().
199
200 IPPrefix() = default;
201 IPPrefix(const IPPrefix&) = default;
202 IPPrefix(IPPrefix&&) = default;
203
204 explicit IPPrefix(const IPAddress& ip) : mData(ip.mData) {}
205
206 // Truncate the IP address |ip| at length |length|. Lengths greater than
207 // the address-family-relevant maximum, along with negative values, are
208 // interpreted as if the address-family-relevant maximum had been given.
209 IPPrefix(const IPAddress& ip, int length);
210
211 IPPrefix& operator=(const IPPrefix&) = default;
212 IPPrefix& operator=(IPPrefix&&) = default;
213
214 constexpr sa_family_t family() const noexcept { return mData.family; }
215 IPAddress ip() const noexcept { return IPAddress(mData); }
Mike Yu0ae31af2018-11-15 21:58:19 +0800216 in_addr addr4() const noexcept { return mData.ip.v4; }
217 in6_addr addr6() const noexcept { return mData.ip.v6; }
Erik Klined26a2c22018-05-11 19:33:19 +0900218 constexpr int length() const noexcept { return mData.cidrlen; }
219
nuccachenf52f7a52018-07-17 18:07:23 +0800220 bool isUninitialized() const noexcept;
Erik Klined26a2c22018-05-11 19:33:19 +0900221 std::string toString() const noexcept;
222
223 friend std::ostream& operator<<(std::ostream& os, const IPPrefix& prefix) {
224 os << prefix.toString();
225 return os;
226 }
227 friend bool operator==(const IPPrefix& a, const IPPrefix& b) { return (a.mData == b.mData); }
228 friend bool operator!=(const IPPrefix& a, const IPPrefix& b) { return (a.mData != b.mData); }
229 friend bool operator<(const IPPrefix& a, const IPPrefix& b) { return (a.mData < b.mData); }
230 friend bool operator>(const IPPrefix& a, const IPPrefix& b) { return (b.mData < a.mData); }
231 friend bool operator<=(const IPPrefix& a, const IPPrefix& b) { return (a < b) || (a == b); }
232 friend bool operator>=(const IPPrefix& a, const IPPrefix& b) { return (b < a) || (a == b); }
233
234 private:
235 internal_::compact_ipdata mData{};
236};
237
238// An Internet socket address.
239//
240// Cannot represent other types of socket addresses (e.g. UNIX socket address, et cetera).
241class IPSockAddr {
242 public:
243 // TODO: static forString
244
245 IPSockAddr() = default;
246 IPSockAddr(const IPSockAddr&) = default;
247 IPSockAddr(IPSockAddr&&) = default;
248
249 explicit IPSockAddr(const IPAddress& ip) : mData(ip.mData) {}
250 IPSockAddr(const IPAddress& ip, in_port_t port) : mData(ip.mData) { mData.port = port; }
251 explicit IPSockAddr(const sockaddr_in& ipv4sa)
252 : IPSockAddr(IPAddress(ipv4sa.sin_addr), ntohs(ipv4sa.sin_port)) {}
253 explicit IPSockAddr(const sockaddr_in6& ipv6sa)
254 : IPSockAddr(IPAddress(ipv6sa.sin6_addr, ipv6sa.sin6_scope_id), ntohs(ipv6sa.sin6_port)) {}
255
256 IPSockAddr& operator=(const IPSockAddr&) = default;
257 IPSockAddr& operator=(IPSockAddr&&) = default;
258
259 constexpr sa_family_t family() const noexcept { return mData.family; }
260 IPAddress ip() const noexcept { return IPAddress(mData); }
261 constexpr in_port_t port() const noexcept { return mData.port; }
262
263 // Implicit conversion to sockaddr_storage.
264 operator sockaddr_storage() const noexcept {
265 sockaddr_storage ss;
266 ss.ss_family = mData.family;
267 switch (mData.family) {
268 case AF_INET:
269 reinterpret_cast<sockaddr_in*>(&ss)->sin_addr = mData.ip.v4;
270 reinterpret_cast<sockaddr_in*>(&ss)->sin_port = htons(mData.port);
271 break;
272 case AF_INET6:
273 reinterpret_cast<sockaddr_in6*>(&ss)->sin6_addr = mData.ip.v6;
274 reinterpret_cast<sockaddr_in6*>(&ss)->sin6_port = htons(mData.port);
275 reinterpret_cast<sockaddr_in6*>(&ss)->sin6_scope_id = mData.scope_id;
276 break;
277 }
278 return ss;
279 }
280
281 std::string toString() const noexcept;
282
283 friend std::ostream& operator<<(std::ostream& os, const IPSockAddr& prefix) {
284 os << prefix.toString();
285 return os;
286 }
287 friend bool operator==(const IPSockAddr& a, const IPSockAddr& b) {
288 return (a.mData == b.mData);
289 }
290 friend bool operator!=(const IPSockAddr& a, const IPSockAddr& b) {
291 return (a.mData != b.mData);
292 }
293 friend bool operator<(const IPSockAddr& a, const IPSockAddr& b) { return (a.mData < b.mData); }
294 friend bool operator>(const IPSockAddr& a, const IPSockAddr& b) { return (b.mData < a.mData); }
295 friend bool operator<=(const IPSockAddr& a, const IPSockAddr& b) { return (a < b) || (a == b); }
296 friend bool operator>=(const IPSockAddr& a, const IPSockAddr& b) { return (b < a) || (a == b); }
297
298 private:
299 internal_::compact_ipdata mData{};
300};
301
302} // namespace netdutils
303} // namespace android