blob: 5785f93039815739ed729e5f5b483a1fb0573e6e [file] [log] [blame]
Adrien Béraud612b55b2023-05-29 10:42:04 -04001/*
2 * Copyright (C) 2004-2023 Savoir-faire Linux Inc.
3 *
Adrien Béraudcb753622023-07-17 22:32:49 -04004 * This program is free software: you can redistribute it and/or modify
Adrien Béraud612b55b2023-05-29 10:42:04 -04005 * it under the terms of the GNU General Public License as published by
Adrien Béraudcb753622023-07-17 22:32:49 -04006 * the Free Software Foundation, either version 3 of the License, or
Adrien Béraud612b55b2023-05-29 10:42:04 -04007 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Adrien Béraudcb753622023-07-17 22:32:49 -040011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Adrien Béraud612b55b2023-05-29 10:42:04 -040012 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17#pragma once
18
Adrien Béraud612b55b2023-05-29 10:42:04 -040019#include <sstream> // include before pjlib.h to fix macros issues with pjlib.h
20
21extern "C" {
22#include <pjlib.h>
23}
24
25#include <ciso646> // fix windows compiler bug
26
27#ifdef _WIN32
28#ifdef RING_UWP
29#define _WIN32_WINNT 0x0A00
30#else
31#define _WIN32_WINNT 0x0601
32#endif
33#include <ws2tcpip.h>
34
35// define in mingw
36#ifdef interface
37#undef interface
38#endif
39#else
40#include <sys/socket.h>
41#include <netinet/in.h>
42#include <arpa/inet.h>
43#include <net/if.h>
44#include <sys/ioctl.h>
45#include <unistd.h>
46#endif
47
48#include <string>
49#include <vector>
50
51/* An IPv4 equivalent to IN6_IS_ADDR_UNSPECIFIED */
52#ifndef IN_IS_ADDR_UNSPECIFIED
53#define IN_IS_ADDR_UNSPECIFIED(a) (((long int) (a)->s_addr) == 0x00000000)
54#endif /* IN_IS_ADDR_UNSPECIFIED */
55
56#define INVALID_SOCKET (-1)
57
Adrien Béraud1ae60aa2023-07-07 09:55:09 -040058namespace dhtnet {
Adrien Béraud612b55b2023-05-29 10:42:04 -040059
60/**
61 * Binary representation of an IP address.
62 */
63class IpAddr
64{
65public:
66 IpAddr()
67 : IpAddr(AF_UNSPEC)
68 {}
69 IpAddr(const IpAddr&) = default;
70 IpAddr(IpAddr&&) = default;
71 IpAddr& operator=(const IpAddr&) = default;
72 IpAddr& operator=(IpAddr&&) = default;
73
74 explicit IpAddr(uint16_t family)
75 : addr()
76 {
77 addr.addr.sa_family = family;
78 }
79
80 IpAddr(const pj_sockaddr& ip)
81 : addr(ip)
82 {}
83
84 IpAddr(const pj_sockaddr& ip, socklen_t len)
85 : addr()
86 {
87 if (len > static_cast<socklen_t>(sizeof(addr)))
88 throw std::invalid_argument("IpAddr(): length overflows internal storage type");
89 memcpy(&addr, &ip, len);
90 }
91
92 IpAddr(const sockaddr& ip)
93 : addr()
94 {
95 memcpy(&addr, &ip, ip.sa_family == AF_INET6 ? sizeof addr.ipv6 : sizeof addr.ipv4);
96 }
97
98 IpAddr(const sockaddr_in& ip)
99 : addr()
100 {
101 static_assert(sizeof(ip) <= sizeof(addr), "sizeof(sockaddr_in) too large");
102 memcpy(&addr, &ip, sizeof(sockaddr_in));
103 }
104
105 IpAddr(const sockaddr_in6& ip)
106 : addr()
107 {
108 static_assert(sizeof(ip) <= sizeof(addr), "sizeof(sockaddr_in6) too large");
109 memcpy(&addr, &ip, sizeof(sockaddr_in6));
110 }
111
112 IpAddr(const sockaddr_storage& ip)
113 : IpAddr(*reinterpret_cast<const sockaddr*>(&ip))
114 {}
115
116 IpAddr(const in_addr& ip)
117 : addr()
118 {
119 static_assert(sizeof(ip) <= sizeof(addr), "sizeof(in_addr) too large");
120 addr.addr.sa_family = AF_INET;
121 memcpy(&addr.ipv4.sin_addr, &ip, sizeof(in_addr));
122 }
123
124 IpAddr(const in6_addr& ip)
125 : addr()
126 {
127 static_assert(sizeof(ip) <= sizeof(addr), "sizeof(in6_addr) too large");
128 addr.addr.sa_family = AF_INET6;
129 memcpy(&addr.ipv6.sin6_addr, &ip, sizeof(in6_addr));
130 }
131
132 IpAddr(std::string_view str, pj_uint16_t family = AF_UNSPEC)
133 : addr()
134 {
135 if (str.empty()) {
136 addr.addr.sa_family = AF_UNSPEC;
137 return;
138 }
139 const pj_str_t pjstring {(char*) str.data(), (pj_ssize_t) str.size()};
140 auto status = pj_sockaddr_parse(family, 0, &pjstring, &addr);
141 if (status != PJ_SUCCESS)
142 addr.addr.sa_family = AF_UNSPEC;
143 }
144
145 // Is defined
146 inline explicit operator bool() const { return isIpv4() or isIpv6(); }
147
148 inline explicit operator bool() { return isIpv4() or isIpv6(); }
149
150 inline operator pj_sockaddr&() { return addr; }
151
152 inline operator const pj_sockaddr&() const { return addr; }
153
154 inline operator pj_sockaddr_in&() { return addr.ipv4; }
155
156 inline operator const pj_sockaddr_in&() const
157 {
158 assert(addr.addr.sa_family != AF_INET6);
159 return addr.ipv4;
160 }
161
162 inline operator pj_sockaddr_in6&() { return addr.ipv6; }
163
164 inline operator const pj_sockaddr_in6&() const
165 {
166 assert(addr.addr.sa_family == AF_INET6);
167 return addr.ipv6;
168 }
169
170 inline operator const sockaddr&() const { return reinterpret_cast<const sockaddr&>(addr); }
171
172 inline operator const sockaddr*() const { return reinterpret_cast<const sockaddr*>(&addr); }
173
174 inline const pj_sockaddr* pjPtr() const { return &addr; }
175
176 inline pj_sockaddr* pjPtr() { return &addr; }
177
178 inline operator std::string() const { return toString(); }
179
180 std::string toString(bool include_port = false, bool force_ipv6_brackets = false) const
181 {
182 if (addr.addr.sa_family == AF_UNSPEC)
183 return {};
184 std::string str(PJ_INET6_ADDRSTRLEN, (char) 0);
185 if (include_port)
186 force_ipv6_brackets = true;
187 pj_sockaddr_print(&addr,
188 &(*str.begin()),
189 PJ_INET6_ADDRSTRLEN,
190 (include_port ? 1 : 0) | (force_ipv6_brackets ? 2 : 0));
191 str.resize(std::char_traits<char>::length(str.c_str()));
192 return str;
193 }
194
195 void setPort(uint16_t port) { pj_sockaddr_set_port(&addr, port); }
196
197 inline uint16_t getPort() const
198 {
199 if (not *this)
200 return 0;
201 return pj_sockaddr_get_port(&addr);
202 }
203
204 inline socklen_t getLength() const
205 {
206 if (not *this)
207 return 0;
208 return pj_sockaddr_get_len(&addr);
209 }
210
211 inline uint16_t getFamily() const { return addr.addr.sa_family; }
212
213 inline bool isIpv4() const { return addr.addr.sa_family == AF_INET; }
214
215 inline bool isIpv6() const { return addr.addr.sa_family == AF_INET6; }
216
217 /**
218 * Return true if address is a loopback IP address.
219 */
220 bool isLoopback() const;
221
222 /**
223 * Return true if address is not a public IP address.
224 */
225 bool isPrivate() const;
226
227 bool isUnspecified() const;
228
229 /**
230 * Return true if address is a valid IPv6.
231 */
232 inline static bool isIpv6(std::string_view address) { return isValid(address, AF_INET6); }
233
234 /**
235 * Return true if address is a valid IP address of specified family (if provided) or of any kind
236 * (default). Does not resolve hostnames.
237 */
238 static bool isValid(std::string_view address, pj_uint16_t family = pj_AF_UNSPEC());
239
240private:
241 pj_sockaddr addr {};
242};
243
244// IpAddr helpers
245inline bool
246operator==(const IpAddr& lhs, const IpAddr& rhs)
247{
248 return !pj_sockaddr_cmp(&lhs, &rhs);
249}
250inline bool
251operator!=(const IpAddr& lhs, const IpAddr& rhs)
252{
253 return !(lhs == rhs);
254}
255inline bool
256operator<(const IpAddr& lhs, const IpAddr& rhs)
257{
258 return pj_sockaddr_cmp(&lhs, &rhs) < 0;
259}
260inline bool
261operator>(const IpAddr& lhs, const IpAddr& rhs)
262{
263 return pj_sockaddr_cmp(&lhs, &rhs) > 0;
264}
265inline bool
266operator<=(const IpAddr& lhs, const IpAddr& rhs)
267{
268 return pj_sockaddr_cmp(&lhs, &rhs) <= 0;
269}
270inline bool
271operator>=(const IpAddr& lhs, const IpAddr& rhs)
272{
273 return pj_sockaddr_cmp(&lhs, &rhs) >= 0;
274}
275
276namespace ip_utils {
277
278static const char* const DEFAULT_INTERFACE = "default";
279
280static const unsigned int MAX_INTERFACE = 256;
281static const unsigned int MIN_INTERFACE = 1;
282enum class subnet_mask { prefix_8bit, prefix_16bit, prefix_24bit, prefix_32bit };
283
284std::string getHostname();
285
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400286struct IpInterfaceAddress
287{
288 std::string interface;
289 std::string address;
290};
291IpInterfaceAddress getHostName();
292std::string getGateway(std::string_view localHost, ip_utils::subnet_mask prefix);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400293IpAddr getLocalGateway();
294
295/**
296 * Return the generic "any host" IP address of the specified family.
297 * If family is unspecified, default to pj_AF_INET6() (IPv6).
298 */
299inline IpAddr
300getAnyHostAddr(pj_uint16_t family)
301{
302 return IpAddr(family);
303}
304
305/**
306 * Return the first host IP address of the specified family.
307 * If no address of the specified family is found, another family will
308 * be tried.
309 * Ex. : if family is pj_AF_INET6() (IPv6/default) and the system does not
310 * have an IPv6 address, an IPv4 address will be returned if available.
311 *
312 * If family is unspecified, default to pj_AF_INET6() if compiled
313 * with IPv6, or pj_AF_INET() otherwise.
314 */
315IpAddr getLocalAddr(pj_uint16_t family);
316
317/**
318 * Get the IP address of the network interface interface with the specified
319 * address family, or of any address family if unspecified (default).
320 */
321IpAddr getInterfaceAddr(const std::string& interface, pj_uint16_t family);
322
323/**
324 * List all the interfaces on the system and return
325 * a vector list containing their name (eth0, eth0:1 ...).
326 * @param void
327 * @return std::vector<std::string> A std::string vector
328 * of interface name available on all of the interfaces on
329 * the system.
330 */
331std::vector<std::string> getAllIpInterfaceByName();
332
333/**
334 * List all the interfaces on the system and return
335 * a vector list containing their IP address.
336 * @param void
337 * @return std::vector<std::string> A std::string vector
338 * of IP address available on all of the interfaces on
339 * the system.
340 */
341std::vector<std::string> getAllIpInterface();
342
343std::vector<IpAddr> getAddrList(std::string_view name, pj_uint16_t family = pj_AF_UNSPEC());
344
345bool haveCommonAddr(const std::vector<IpAddr>& a, const std::vector<IpAddr>& b);
346
347std::vector<IpAddr> getLocalNameservers();
348
349} // namespace ip_utils
Sébastien Blin464bdff2023-07-19 08:02:53 -0400350} // namespace dhtnet