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