blob: 0ef6dd0e75aa2eeafe9ed20defd998248b7f7670 [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
17#ifndef NETDUTILS_INTERNETADDRESSES_H_
18#define NETDUTILS_INTERNETADDRESSES_H_
19
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
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};
37 uint8_t cidrlen{0U};
38 in_port_t port{0U};
39 uint32_t scope_id{0U};
40 union {
41 in_addr v4;
42 in6_addr v6;
43 } ip{.v6 = IN6ADDR_ANY_INIT};
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) {
53 case AF_INET: {
54 // Address of packed member may not have correct alignment.
55 const in_addr v4a = a.ip.v4;
56 const in_addr v4b = b.ip.v4;
57 if (v4a.s_addr != v4b.s_addr) return false;
58 break;
59 }
60 case AF_INET6: {
61 // Address of packed member may not have correct alignment.
62 const in6_addr v6a = a.ip.v6;
63 const in6_addr v6b = b.ip.v6;
64 if (std::memcmp(v6a.s6_addr, v6b.s6_addr, IPV6_ADDR_LEN) != 0) return false;
65 break;
66 }
67 }
68 return true;
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: {
81 // Address of packed member may not have correct alignment.
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 // Address of packed member may not have correct alignment.
89 const in6_addr v6a = a.ip.v6;
90 const in6_addr v6b = b.ip.v6;
91 const int cmp = memcmp(v6a.s6_addr, v6b.s6_addr, IPV6_ADDR_LEN);
92 if (cmp != 0) return cmp < 0;
93 break;
94 }
95 }
96 if (a.cidrlen != b.cidrlen) return (a.cidrlen < b.cidrlen);
97 if (a.port != b.port) return (a.port < b.port);
98 return (a.scope_id < b.scope_id);
99 }
100};
101
102static_assert(AF_UNSPEC <= std::numeric_limits<uint8_t>::max(), "AF_UNSPEC value too large");
103static_assert(AF_INET <= std::numeric_limits<uint8_t>::max(), "AF_INET value too large");
104static_assert(AF_INET6 <= std::numeric_limits<uint8_t>::max(), "AF_INET6 value too large");
105static_assert(sizeof(compact_ipdata) == 24U, "compact_ipdata unexpectedly large");
106
107} // namespace internal_
108
109inline bool isLinkLocal(const in6_addr& ipv6) {
110 return (IN6_IS_ADDR_LINKLOCAL(&ipv6) || IN6_IS_ADDR_MC_LINKLOCAL(&ipv6));
111}
112
113class IPPrefix;
114class IPSockAddr;
115
116class IPAddress {
117 public:
118 static bool forString(const std::string& repr, IPAddress* ip);
119 static IPAddress forString(const std::string& repr) {
120 IPAddress ip;
121 if (!forString(repr, &ip)) return IPAddress();
122 return ip;
123 }
124
125 IPAddress() = default;
126 IPAddress(const IPAddress&) = default;
127 IPAddress(IPAddress&&) = default;
128
129 explicit IPAddress(const in_addr& ipv4)
130 : mData({AF_INET, IPV4_ADDR_BITS, 0U, 0U, {.v4 = ipv4}}) {}
131 explicit IPAddress(const in6_addr& ipv6)
132 : mData({AF_INET6, IPV6_ADDR_BITS, 0U, 0U, {.v6 = ipv6}}) {}
133 IPAddress(const in6_addr& ipv6, uint32_t scope_id)
134 : mData({AF_INET6,
135 IPV6_ADDR_BITS,
136 0U,
137 // Sanity check: scoped_ids only for link-local addresses.
138 isLinkLocal(ipv6) ? scope_id : 0U,
139 {.v6 = ipv6}}) {}
140 IPAddress(const IPAddress& ip, uint32_t scope_id) : IPAddress(ip) {
141 mData.scope_id = (family() == AF_INET6 && isLinkLocal(mData.ip.v6)) ? scope_id : 0U;
142 }
143
144 IPAddress& operator=(const IPAddress&) = default;
145 IPAddress& operator=(IPAddress&&) = default;
146
147 constexpr sa_family_t family() const noexcept { return mData.family; }
148 constexpr uint32_t scope_id() const noexcept { return mData.scope_id; }
149
150 std::string toString() const noexcept;
151
152 friend std::ostream& operator<<(std::ostream& os, const IPAddress& ip) {
153 os << ip.toString();
154 return os;
155 }
156 friend bool operator==(const IPAddress& a, const IPAddress& b) { return (a.mData == b.mData); }
157 friend bool operator!=(const IPAddress& a, const IPAddress& b) { return (a.mData != b.mData); }
158 friend bool operator<(const IPAddress& a, const IPAddress& b) { return (a.mData < b.mData); }
159 friend bool operator>(const IPAddress& a, const IPAddress& b) { return (b.mData < a.mData); }
160 friend bool operator<=(const IPAddress& a, const IPAddress& b) { return (a < b) || (a == b); }
161 friend bool operator>=(const IPAddress& a, const IPAddress& b) { return (b < a) || (a == b); }
162
163 private:
164 friend class IPPrefix;
165 friend class IPSockAddr;
166
167 explicit IPAddress(const internal_::compact_ipdata& ipdata) : mData(ipdata) {
168 mData.port = 0U;
169 switch (mData.family) {
170 case AF_INET:
171 mData.cidrlen = IPV4_ADDR_BITS;
172 mData.scope_id = 0U;
173 break;
174 case AF_INET6:
175 mData.cidrlen = IPV6_ADDR_BITS;
176 if (isLinkLocal(ipdata.ip.v6)) mData.scope_id = ipdata.scope_id;
177 break;
178 default:
179 mData.cidrlen = 0U;
180 mData.scope_id = 0U;
181 break;
182 }
183 }
184
185 internal_::compact_ipdata mData{};
186};
187
188class IPPrefix {
189 public:
190 // TODO: "static forString(...)" using NetdConstants' parsePrefix().
191
192 IPPrefix() = default;
193 IPPrefix(const IPPrefix&) = default;
194 IPPrefix(IPPrefix&&) = default;
195
196 explicit IPPrefix(const IPAddress& ip) : mData(ip.mData) {}
197
198 // Truncate the IP address |ip| at length |length|. Lengths greater than
199 // the address-family-relevant maximum, along with negative values, are
200 // interpreted as if the address-family-relevant maximum had been given.
201 IPPrefix(const IPAddress& ip, int length);
202
203 IPPrefix& operator=(const IPPrefix&) = default;
204 IPPrefix& operator=(IPPrefix&&) = default;
205
206 constexpr sa_family_t family() const noexcept { return mData.family; }
207 IPAddress ip() const noexcept { return IPAddress(mData); }
208 constexpr int length() const noexcept { return mData.cidrlen; }
209
210 std::string toString() const noexcept;
211
212 friend std::ostream& operator<<(std::ostream& os, const IPPrefix& prefix) {
213 os << prefix.toString();
214 return os;
215 }
216 friend bool operator==(const IPPrefix& a, const IPPrefix& b) { return (a.mData == b.mData); }
217 friend bool operator!=(const IPPrefix& a, const IPPrefix& b) { return (a.mData != b.mData); }
218 friend bool operator<(const IPPrefix& a, const IPPrefix& b) { return (a.mData < b.mData); }
219 friend bool operator>(const IPPrefix& a, const IPPrefix& b) { return (b.mData < a.mData); }
220 friend bool operator<=(const IPPrefix& a, const IPPrefix& b) { return (a < b) || (a == b); }
221 friend bool operator>=(const IPPrefix& a, const IPPrefix& b) { return (b < a) || (a == b); }
222
223 private:
224 internal_::compact_ipdata mData{};
225};
226
227// An Internet socket address.
228//
229// Cannot represent other types of socket addresses (e.g. UNIX socket address, et cetera).
230class IPSockAddr {
231 public:
232 // TODO: static forString
233
234 IPSockAddr() = default;
235 IPSockAddr(const IPSockAddr&) = default;
236 IPSockAddr(IPSockAddr&&) = default;
237
238 explicit IPSockAddr(const IPAddress& ip) : mData(ip.mData) {}
239 IPSockAddr(const IPAddress& ip, in_port_t port) : mData(ip.mData) { mData.port = port; }
240 explicit IPSockAddr(const sockaddr_in& ipv4sa)
241 : IPSockAddr(IPAddress(ipv4sa.sin_addr), ntohs(ipv4sa.sin_port)) {}
242 explicit IPSockAddr(const sockaddr_in6& ipv6sa)
243 : IPSockAddr(IPAddress(ipv6sa.sin6_addr, ipv6sa.sin6_scope_id), ntohs(ipv6sa.sin6_port)) {}
244
245 IPSockAddr& operator=(const IPSockAddr&) = default;
246 IPSockAddr& operator=(IPSockAddr&&) = default;
247
248 constexpr sa_family_t family() const noexcept { return mData.family; }
249 IPAddress ip() const noexcept { return IPAddress(mData); }
250 constexpr in_port_t port() const noexcept { return mData.port; }
251
252 // Implicit conversion to sockaddr_storage.
253 operator sockaddr_storage() const noexcept {
254 sockaddr_storage ss;
255 ss.ss_family = mData.family;
256 switch (mData.family) {
257 case AF_INET:
258 reinterpret_cast<sockaddr_in*>(&ss)->sin_addr = mData.ip.v4;
259 reinterpret_cast<sockaddr_in*>(&ss)->sin_port = htons(mData.port);
260 break;
261 case AF_INET6:
262 reinterpret_cast<sockaddr_in6*>(&ss)->sin6_addr = mData.ip.v6;
263 reinterpret_cast<sockaddr_in6*>(&ss)->sin6_port = htons(mData.port);
264 reinterpret_cast<sockaddr_in6*>(&ss)->sin6_scope_id = mData.scope_id;
265 break;
266 }
267 return ss;
268 }
269
270 std::string toString() const noexcept;
271
272 friend std::ostream& operator<<(std::ostream& os, const IPSockAddr& prefix) {
273 os << prefix.toString();
274 return os;
275 }
276 friend bool operator==(const IPSockAddr& a, const IPSockAddr& b) {
277 return (a.mData == b.mData);
278 }
279 friend bool operator!=(const IPSockAddr& a, const IPSockAddr& b) {
280 return (a.mData != b.mData);
281 }
282 friend bool operator<(const IPSockAddr& a, const IPSockAddr& b) { return (a.mData < b.mData); }
283 friend bool operator>(const IPSockAddr& a, const IPSockAddr& b) { return (b.mData < a.mData); }
284 friend bool operator<=(const IPSockAddr& a, const IPSockAddr& b) { return (a < b) || (a == b); }
285 friend bool operator>=(const IPSockAddr& a, const IPSockAddr& b) { return (b < a) || (a == b); }
286
287 private:
288 internal_::compact_ipdata mData{};
289};
290
291} // namespace netdutils
292} // namespace android
293
294#endif // NETDUTILS_INTERNETADDRESSES_H_