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