• 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 #pragma once
18 
19 #include <netdb.h>
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 
107 struct AddrinfoDeleter {
operatorAddrinfoDeleter108     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 
usesScopedIds(const in6_addr & ipv6)117 inline bool usesScopedIds(const in6_addr& ipv6) {
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);
forString(const std::string & repr)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 
IPAddress(const in_addr & ipv4)137     explicit IPAddress(const in_addr& ipv4)
138         : mData({AF_INET, IPV4_ADDR_BITS, 0U, 0U, {.v4 = ipv4}}) {}
IPAddress(const in6_addr & ipv6)139     explicit IPAddress(const in6_addr& ipv6)
140         : mData({AF_INET6, IPV6_ADDR_BITS, 0U, 0U, {.v6 = ipv6}}) {}
IPAddress(const in6_addr & ipv6,uint32_t scope_id)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.
146                  usesScopedIds(ipv6) ? scope_id : 0U,
147                  {.v6 = ipv6}}) {}
IPAddress(const IPAddress & ip,uint32_t scope_id)148     IPAddress(const IPAddress& ip, uint32_t scope_id) : IPAddress(ip) {
149         mData.scope_id = (family() == AF_INET6 && usesScopedIds(mData.ip.v6)) ? scope_id : 0U;
150     }
151 
152     IPAddress& operator=(const IPAddress&) = default;
153     IPAddress& operator=(IPAddress&&) = default;
154 
family()155     constexpr sa_family_t family() const noexcept { return mData.family; }
scope_id()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 
IPAddress(const internal_::compact_ipdata & ipdata)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;
184                 if (usesScopedIds(ipdata.ip.v6)) mData.scope_id = ipdata.scope_id;
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:
198     static bool forString(const std::string& repr, IPPrefix* prefix);
forString(const std::string & repr)199     static IPPrefix forString(const std::string& repr) {
200         IPPrefix prefix;
201         if (!forString(repr, &prefix)) return IPPrefix();
202         return prefix;
203     }
204 
205     IPPrefix() = default;
206     IPPrefix(const IPPrefix&) = default;
207     IPPrefix(IPPrefix&&) = default;
208 
IPPrefix(const IPAddress & ip)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 
family()219     constexpr sa_family_t family() const noexcept { return mData.family; }
ip()220     IPAddress ip() const noexcept { return IPAddress(mData); }
addr4()221     in_addr addr4() const noexcept { return mData.ip.v4; }
addr6()222     in6_addr addr6() const noexcept { return mData.ip.v6; }
length()223     constexpr int length() const noexcept { return mData.cidrlen; }
contains(const IPPrefix & other)224     bool contains(const IPPrefix& other) {
225         return length() <= other.length() && IPPrefix(other.ip(), length()).ip() == ip();
226     }
contains(const IPAddress & other)227     bool contains(const IPAddress& other) {
228         return IPPrefix(other, length()).ip() == ip();
229     }
230 
231     bool isUninitialized() const noexcept;
232     std::string toString() const noexcept;
233 
234     friend std::ostream& operator<<(std::ostream& os, const IPPrefix& prefix) {
235         os << prefix.toString();
236         return os;
237     }
238     friend bool operator==(const IPPrefix& a, const IPPrefix& b) { return (a.mData == b.mData); }
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 (b.mData < a.mData); }
242     friend bool operator<=(const IPPrefix& a, const IPPrefix& b) { return (a < b) || (a == b); }
243     friend bool operator>=(const IPPrefix& a, const IPPrefix& b) { return (b < a) || (a == b); }
244 
245   private:
246     internal_::compact_ipdata mData{};
247 };
248 
249 // An Internet socket address.
250 //
251 // Cannot represent other types of socket addresses (e.g. UNIX socket address, et cetera).
252 class IPSockAddr {
253   public:
254     // TODO: static forString
255 
toIPSockAddr(const std::string & repr,in_port_t port)256     static IPSockAddr toIPSockAddr(const std::string& repr, in_port_t port) {
257         return IPSockAddr(IPAddress::forString(repr), port);
258     }
toIPSockAddr(const sockaddr & sa)259     static IPSockAddr toIPSockAddr(const sockaddr& sa) {
260         switch (sa.sa_family) {
261             case AF_INET:
262                 return IPSockAddr(*reinterpret_cast<const sockaddr_in*>(&sa));
263             case AF_INET6:
264                 return IPSockAddr(*reinterpret_cast<const sockaddr_in6*>(&sa));
265             default:
266                 return IPSockAddr();
267         }
268     }
toIPSockAddr(const sockaddr_storage & ss)269     static IPSockAddr toIPSockAddr(const sockaddr_storage& ss) {
270         return toIPSockAddr(*reinterpret_cast<const sockaddr*>(&ss));
271     }
272 
273     IPSockAddr() = default;
274     IPSockAddr(const IPSockAddr&) = default;
275     IPSockAddr(IPSockAddr&&) = default;
276 
IPSockAddr(const IPAddress & ip)277     explicit IPSockAddr(const IPAddress& ip) : mData(ip.mData) {}
IPSockAddr(const IPAddress & ip,in_port_t port)278     IPSockAddr(const IPAddress& ip, in_port_t port) : mData(ip.mData) { mData.port = port; }
IPSockAddr(const sockaddr_in & ipv4sa)279     explicit IPSockAddr(const sockaddr_in& ipv4sa)
280         : IPSockAddr(IPAddress(ipv4sa.sin_addr), ntohs(ipv4sa.sin_port)) {}
IPSockAddr(const sockaddr_in6 & ipv6sa)281     explicit IPSockAddr(const sockaddr_in6& ipv6sa)
282         : IPSockAddr(IPAddress(ipv6sa.sin6_addr, ipv6sa.sin6_scope_id), ntohs(ipv6sa.sin6_port)) {}
283 
284     IPSockAddr& operator=(const IPSockAddr&) = default;
285     IPSockAddr& operator=(IPSockAddr&&) = default;
286 
family()287     constexpr sa_family_t family() const noexcept { return mData.family; }
ip()288     IPAddress ip() const noexcept { return IPAddress(mData); }
port()289     constexpr in_port_t port() const noexcept { return mData.port; }
290 
291     // Implicit conversion to sockaddr_storage.
sockaddr_storage()292     operator sockaddr_storage() const noexcept {
293         sockaddr_storage ss;
294         ss.ss_family = mData.family;
295         switch (mData.family) {
296             case AF_INET:
297                 reinterpret_cast<sockaddr_in*>(&ss)->sin_addr = mData.ip.v4;
298                 reinterpret_cast<sockaddr_in*>(&ss)->sin_port = htons(mData.port);
299                 break;
300             case AF_INET6:
301                 reinterpret_cast<sockaddr_in6*>(&ss)->sin6_addr = mData.ip.v6;
302                 reinterpret_cast<sockaddr_in6*>(&ss)->sin6_port = htons(mData.port);
303                 reinterpret_cast<sockaddr_in6*>(&ss)->sin6_scope_id = mData.scope_id;
304                 break;
305         }
306         return ss;
307     }
308 
309     std::string toString() const noexcept;
310 
311     friend std::ostream& operator<<(std::ostream& os, const IPSockAddr& prefix) {
312         os << prefix.toString();
313         return os;
314     }
315     friend bool operator==(const IPSockAddr& a, const IPSockAddr& b) {
316         return (a.mData == b.mData);
317     }
318     friend bool operator!=(const IPSockAddr& a, const IPSockAddr& b) {
319         return (a.mData != b.mData);
320     }
321     friend bool operator<(const IPSockAddr& a, const IPSockAddr& b) { return (a.mData < b.mData); }
322     friend bool operator>(const IPSockAddr& a, const IPSockAddr& b) { return (b.mData < a.mData); }
323     friend bool operator<=(const IPSockAddr& a, const IPSockAddr& b) { return (a < b) || (a == b); }
324     friend bool operator>=(const IPSockAddr& a, const IPSockAddr& b) { return (b < a) || (a == b); }
325 
326   private:
327     internal_::compact_ipdata mData{};
328 };
329 
330 }  // namespace netdutils
331 }  // namespace android
332