blob: 25e1f406d97ba9d75eee7d1dd32d5ec3fa931ca5 [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
Adrien Béraudcb753622023-07-17 22:32:49 -040015 * along with this program. If not, see <https://www.gnu.org/licenses/>.
Adrien Béraud612b55b2023-05-29 10:42:04 -040016 */
Adrien Béraud612b55b2023-05-29 10:42:04 -040017#include "ip_utils.h"
Adrien Béraud80c14e12023-07-18 16:13:15 -040018#include "sip_utils.h"
19#include "string_utils.h"
Adrien Béraud612b55b2023-05-29 10:42:04 -040020
Adrien Béraud80c14e12023-07-18 16:13:15 -040021#include <fmt/format.h>
Adrien Béraud612b55b2023-05-29 10:42:04 -040022
Adrien Béraud4822fa02023-07-30 00:21:05 -040023extern "C" {
Adrien Béraud612b55b2023-05-29 10:42:04 -040024#include <sys/types.h>
25#include <unistd.h>
26#include <limits.h>
27
28#ifdef _WIN32
29#define InetPtonA inet_pton
30WINSOCK_API_LINKAGE INT WSAAPI InetPtonA(INT Family, LPCSTR pStringBuf, PVOID pAddr);
31#else
32#include <arpa/inet.h>
33#include <arpa/nameser.h>
34#include <resolv.h>
35#include <netdb.h>
36#include <netinet/ip.h>
37#include <net/if.h>
38#include <ifaddrs.h>
39#include <sys/ioctl.h>
40#endif
Adrien Béraud4822fa02023-07-30 00:21:05 -040041}
Adrien Béraud612b55b2023-05-29 10:42:04 -040042
43#ifndef HOST_NAME_MAX
44#ifdef MAX_COMPUTERNAME_LENGTH
45#define HOST_NAME_MAX MAX_COMPUTERNAME_LENGTH
46#else
47// Max 255 chars as per RFC 1035
48#define HOST_NAME_MAX 255
49#endif
50#endif
51
Adrien Béraud1ae60aa2023-07-07 09:55:09 -040052namespace dhtnet {
Adrien Béraud612b55b2023-05-29 10:42:04 -040053
Adrien Béraud9ed4dd92023-07-19 00:13:05 -040054namespace sip_utils {
Adrien Béraud612b55b2023-05-29 10:42:04 -040055std::string_view
56sip_strerror(pj_status_t code)
57{
58 thread_local char err_msg[PJ_ERR_MSG_SIZE];
Adrien Béraud80c14e12023-07-18 16:13:15 -040059 return sip_utils::as_view(pj_strerror(code, err_msg, sizeof err_msg));
Adrien Béraud612b55b2023-05-29 10:42:04 -040060}
Adrien Béraud9ed4dd92023-07-19 00:13:05 -040061}
Adrien Béraud612b55b2023-05-29 10:42:04 -040062
63std::string
64ip_utils::getHostname()
65{
66 char hostname[HOST_NAME_MAX];
67 if (gethostname(hostname, HOST_NAME_MAX))
68 return {};
69 return hostname;
70}
71
Adrien Béraud63a1fac2023-08-23 09:31:17 -040072ip_utils::IpInterfaceAddress
73ip_utils::getHostName()
Adrien Béraud612b55b2023-05-29 10:42:04 -040074{
Adrien Béraud63a1fac2023-08-23 09:31:17 -040075 IpInterfaceAddress ret;
Adrien Béraud612b55b2023-05-29 10:42:04 -040076 char tempstr[INET_ADDRSTRLEN];
77 const char* p = NULL;
78#ifdef _WIN32
79 struct hostent* h = NULL;
80 struct sockaddr_in localAddr;
81 memset(&localAddr, 0, sizeof(localAddr));
Andreas Traczyk24cc01e2023-08-23 18:55:15 -040082 char out[256];
83 if (gethostname(out, sizeof(out)) == SOCKET_ERROR) {
84 return {};
85 }
Adrien Béraud612b55b2023-05-29 10:42:04 -040086 h = gethostbyname(out);
87 if (h != NULL) {
Andreas Traczyk24cc01e2023-08-23 18:55:15 -040088 memcpy(&localAddr.sin_addr, h->h_addr_list[0], sizeof(localAddr.sin_addr));
Adrien Béraud612b55b2023-05-29 10:42:04 -040089 p = inet_ntop(AF_INET, &localAddr.sin_addr, tempstr, sizeof(tempstr));
Andreas Traczyk24cc01e2023-08-23 18:55:15 -040090 if (p) {
Adrien Béraud63a1fac2023-08-23 09:31:17 -040091 ret.address = p;
Andreas Traczyk24cc01e2023-08-23 18:55:15 -040092 }
Adrien Béraud612b55b2023-05-29 10:42:04 -040093 }
94#elif (defined(BSD) && BSD >= 199306) || defined(__FreeBSD_kernel__)
Adrien Béraud612b55b2023-05-29 10:42:04 -040095 struct ifaddrs* ifap;
96 struct ifaddrs* ifa;
Andreas Traczyk24cc01e2023-08-23 18:55:15 -040097 if (getifaddrs(&ifap) != 0) {
Adrien Béraud63a1fac2023-08-23 09:31:17 -040098 return {};
Andreas Traczyk24cc01e2023-08-23 18:55:15 -040099 }
Adrien Béraud612b55b2023-05-29 10:42:04 -0400100 // Cycle through available interfaces.
101 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
102 // Skip loopback, point-to-point and down interfaces.
103 // except don't skip down interfaces if we're trying to get
104 // a list of configurable interfaces.
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400105 if ((ifa->ifa_flags & IFF_LOOPBACK) || (!(ifa->ifa_flags & IFF_UP))) {
Adrien Béraud612b55b2023-05-29 10:42:04 -0400106 continue;
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400107 }
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400108 auto family = ifa->ifa_addr->sa_family;
109 if (family == AF_INET) {
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400110 void* addr = &((struct sockaddr_in*)ifa->ifa_addr)->sin_addr;
111 if (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
112 continue;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400113 }
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400114 ret.interface = ifa->ifa_name;
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400115 p = inet_ntop(family, addr, tempstr, sizeof(tempstr));
116 if (p) {
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400117 ret.address = p;
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400118 }
Adrien Béraud612b55b2023-05-29 10:42:04 -0400119 break;
120 }
121 }
122 freeifaddrs(ifap);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400123#else
124 struct ifconf ifConf;
125 struct ifreq ifReq;
126 struct sockaddr_in localAddr;
127 char szBuffer[MAX_INTERFACE * sizeof(struct ifreq)];
128 int nResult;
129 int localSock;
130 memset(&ifConf, 0, sizeof(ifConf));
131 memset(&ifReq, 0, sizeof(ifReq));
132 memset(szBuffer, 0, sizeof(szBuffer));
133 memset(&localAddr, 0, sizeof(localAddr));
134 // Create an unbound datagram socket to do the SIOCGIFADDR ioctl on.
135 localSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400136 if (localSock == INVALID_SOCKET) {
137 return {};
138 }
Adrien Béraud612b55b2023-05-29 10:42:04 -0400139 /* Get the interface configuration information... */
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400140 ifConf.ifc_len = sizeof(szBuffer);
141 ifConf.ifc_buf = (caddr_t)szBuffer;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400142 nResult = ioctl(localSock, SIOCGIFCONF, &ifConf);
143 if (nResult < 0) {
144 close(localSock);
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400145 return {};
Adrien Béraud612b55b2023-05-29 10:42:04 -0400146 }
147 unsigned int i;
148 unsigned int j = 0;
149 // Cycle through the list of interfaces looking for IP addresses.
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400150 for (i = 0u; i < ifConf.ifc_len && j < MIN_INTERFACE;) {
151 struct ifreq* pifReq = (struct ifreq*)((caddr_t)ifConf.ifc_req + i);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400152 i += sizeof *pifReq;
153 // See if this is the sort of interface we want to deal with.
154 memset(ifReq.ifr_name, 0, sizeof(ifReq.ifr_name));
155 strncpy(ifReq.ifr_name, pifReq->ifr_name, sizeof(ifReq.ifr_name));
156 ioctl(localSock, SIOCGIFFLAGS, &ifReq);
157 // Skip loopback, point-to-point and down interfaces.
158 // except don't skip down interfaces if we're trying to get
159 // a list of configurable interfaces.
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400160 if ((ifReq.ifr_flags & IFF_LOOPBACK) || (!(ifReq.ifr_flags & IFF_UP))) {
Adrien Béraud612b55b2023-05-29 10:42:04 -0400161 continue;
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400162 }
Adrien Béraud612b55b2023-05-29 10:42:04 -0400163 if (pifReq->ifr_addr.sa_family == AF_INET) {
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400164 if (((sockaddr_in*)&pifReq->ifr_addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
Adrien Béraud612b55b2023-05-29 10:42:04 -0400165 // We don't want the loopback interface. Go to the next one.
166 continue;
167 }
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400168 ret.interface = pifReq->ifr_name;
169 p = inet_ntop(pifReq->ifr_addr.sa_family,
Adrien Beraud64bb00f2023-08-23 19:06:46 -0400170 &((sockaddr_in*)&pifReq->ifr_addr)->sin_addr,
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400171 tempstr,
172 sizeof(tempstr));
173 if (p)
174 ret.address = p;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400175 }
176 j++; // Increment j if we found an address which is not loopback and is up.
177 }
178 close(localSock);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400179#endif
Adrien Beraud64bb00f2023-08-23 19:06:46 -0400180 return ret;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400181}
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400182
Adrien Béraud612b55b2023-05-29 10:42:04 -0400183std::string
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400184ip_utils::getGateway(std::string_view localHost, ip_utils::subnet_mask prefix)
Adrien Béraud612b55b2023-05-29 10:42:04 -0400185{
Adrien Béraud612b55b2023-05-29 10:42:04 -0400186 if (prefix == ip_utils::subnet_mask::prefix_32bit)
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400187 return std::string(localHost);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400188 std::string defaultGw {};
189 // Make a vector of each individual number in the ip address.
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400190 std::vector<std::string_view> tokens = split_string(localHost, '.');
Adrien Béraud612b55b2023-05-29 10:42:04 -0400191 // Build a gateway address from the individual ip components.
192 for (unsigned i = 0; i <= (unsigned) prefix; i++)
Adrien Béraud80c14e12023-07-18 16:13:15 -0400193 defaultGw = fmt::format("{:s}{:s}.", defaultGw, tokens[i]);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400194 for (unsigned i = (unsigned) ip_utils::subnet_mask::prefix_32bit;
195 i > (unsigned) prefix + 1;
196 i--)
197 defaultGw += "0.";
198 defaultGw += "1";
199 return defaultGw;
200}
201
202IpAddr
203ip_utils::getLocalGateway()
204{
205 char localHostBuf[INET_ADDRSTRLEN];
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400206 auto hostInfo = ip_utils::getHostName();
207 if (hostInfo.address.empty()) {
Morteza Namvar5f639522023-07-04 17:08:58 -0400208 // JAMI_WARN("Couldn't find local host");
Adrien Béraud612b55b2023-05-29 10:42:04 -0400209 return {};
210 } else {
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400211 return IpAddr(ip_utils::getGateway(hostInfo.address, ip_utils::subnet_mask::prefix_24bit));
Adrien Béraud612b55b2023-05-29 10:42:04 -0400212 }
213}
214
215std::vector<IpAddr>
216ip_utils::getAddrList(std::string_view name, pj_uint16_t family)
217{
218 std::vector<IpAddr> ipList;
219 if (name.empty())
220 return ipList;
221 if (IpAddr::isValid(name, family)) {
222 ipList.emplace_back(name);
223 return ipList;
224 }
225
226 static constexpr unsigned MAX_ADDR_NUM = 128;
227 pj_addrinfo res[MAX_ADDR_NUM];
228 unsigned addr_num = MAX_ADDR_NUM;
229 const pj_str_t pjname(sip_utils::CONST_PJ_STR(name));
230 auto status = pj_getaddrinfo(family, &pjname, &addr_num, res);
231 if (status != PJ_SUCCESS) {
Morteza Namvar5f639522023-07-04 17:08:58 -0400232 // JAMI_ERR("Error resolving %.*s : %s",
233 // (int) name.size(),
234 // name.data(),
235 // sip_utils::sip_strerror(status).c_str());
Adrien Béraud612b55b2023-05-29 10:42:04 -0400236 return ipList;
237 }
238
239 for (unsigned i = 0; i < addr_num; i++) {
240 bool found = false;
241 for (const auto& ip : ipList)
242 if (!pj_sockaddr_cmp(&ip, &res[i].ai_addr)) {
243 found = true;
244 break;
245 }
246 if (!found)
247 ipList.emplace_back(res[i].ai_addr);
248 }
249
250 return ipList;
251}
252
253bool
254ip_utils::haveCommonAddr(const std::vector<IpAddr>& a, const std::vector<IpAddr>& b)
255{
256 for (const auto& i : a) {
257 for (const auto& j : b) {
258 if (i == j)
259 return true;
260 }
261 }
262 return false;
263}
264
265IpAddr
266ip_utils::getLocalAddr(pj_uint16_t family)
267{
268 IpAddr ip_addr {};
269 pj_status_t status = pj_gethostip(family, ip_addr.pjPtr());
270 if (status == PJ_SUCCESS) {
271 return ip_addr;
272 }
Morteza Namvar5f639522023-07-04 17:08:58 -0400273 // JAMI_WARN("Could not get preferred address familly (%s)",
274 // (family == pj_AF_INET6()) ? "IPv6" : "IPv4");
Adrien Béraud612b55b2023-05-29 10:42:04 -0400275 family = (family == pj_AF_INET()) ? pj_AF_INET6() : pj_AF_INET();
276 status = pj_gethostip(family, ip_addr.pjPtr());
277 if (status == PJ_SUCCESS) {
278 return ip_addr;
279 }
Morteza Namvar5f639522023-07-04 17:08:58 -0400280 // JAMI_ERR("Could not get local IP");
Adrien Béraud612b55b2023-05-29 10:42:04 -0400281 return ip_addr;
282}
283
284IpAddr
285ip_utils::getInterfaceAddr(const std::string& interface, pj_uint16_t family)
286{
287 if (interface == DEFAULT_INTERFACE)
288 return getLocalAddr(family);
289
290 IpAddr addr {};
291
292#ifndef _WIN32
293 const auto unix_family = family == pj_AF_INET() ? AF_INET : AF_INET6;
294
295 int fd = socket(unix_family, SOCK_DGRAM, 0);
296 if (fd < 0) {
Morteza Namvar5f639522023-07-04 17:08:58 -0400297 // JAMI_ERR("Could not open socket: %m");
Adrien Béraud612b55b2023-05-29 10:42:04 -0400298 return addr;
299 }
300
301 if (unix_family == AF_INET6) {
302 int val = family != pj_AF_UNSPEC();
303 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*) &val, sizeof(val)) < 0) {
Morteza Namvar5f639522023-07-04 17:08:58 -0400304 // JAMI_ERR("Could not setsockopt: %m");
Adrien Béraud612b55b2023-05-29 10:42:04 -0400305 close(fd);
306 return addr;
307 }
308 }
309
310 ifreq ifr;
311 strncpy(ifr.ifr_name, interface.c_str(), sizeof ifr.ifr_name);
312 // guarantee that ifr_name is NULL-terminated
313 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
314
315 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
316 ifr.ifr_addr.sa_family = unix_family;
317
318 ioctl(fd, SIOCGIFADDR, &ifr);
319 close(fd);
320
321 addr = ifr.ifr_addr;
322 if (addr.isUnspecified())
323 return getLocalAddr(addr.getFamily());
324#else // _WIN32
325 struct addrinfo hints;
326 struct addrinfo* result = NULL;
327 struct sockaddr_in* sockaddr_ipv4;
328 struct sockaddr_in6* sockaddr_ipv6;
329
330 ZeroMemory(&hints, sizeof(hints));
331
332 DWORD dwRetval = getaddrinfo(interface.c_str(), "0", &hints, &result);
333 if (dwRetval != 0) {
Morteza Namvar5f639522023-07-04 17:08:58 -0400334 // JAMI_ERR("getaddrinfo failed with error: %lu", dwRetval);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400335 return addr;
336 }
337
338 switch (result->ai_family) {
339 sockaddr_ipv4 = (struct sockaddr_in*) result->ai_addr;
340 addr = sockaddr_ipv4->sin_addr;
341 break;
342 case AF_INET6:
343 sockaddr_ipv6 = (struct sockaddr_in6*) result->ai_addr;
344 addr = sockaddr_ipv6->sin6_addr;
345 break;
346 default:
347 break;
348 }
349
350 if (addr.isUnspecified())
351 return getLocalAddr(addr.getFamily());
352#endif // !_WIN32
353
354 return addr;
355}
356
357std::vector<std::string>
358ip_utils::getAllIpInterfaceByName()
359{
360 std::vector<std::string> ifaceList;
361 ifaceList.push_back("default");
362#ifndef _WIN32
363 static ifreq ifreqs[20];
364 ifconf ifconf;
365
366 ifconf.ifc_buf = (char*) (ifreqs);
367 ifconf.ifc_len = sizeof(ifreqs);
368
369 int sock = socket(AF_INET6, SOCK_STREAM, 0);
370
371 if (sock >= 0) {
372 if (ioctl(sock, SIOCGIFCONF, &ifconf) >= 0)
373 for (unsigned i = 0; i < ifconf.ifc_len / sizeof(ifreq); ++i)
374 ifaceList.push_back(std::string(ifreqs[i].ifr_name));
375
376 close(sock);
377 }
378
379#else
Morteza Namvar5f639522023-07-04 17:08:58 -0400380 // JAMI_ERR("Not implemented yet. (iphlpapi.h problem)");
Adrien Béraud612b55b2023-05-29 10:42:04 -0400381#endif
382 return ifaceList;
383}
384
385std::vector<std::string>
386ip_utils::getAllIpInterface()
387{
388 pj_sockaddr addrList[16];
389 unsigned addrCnt = PJ_ARRAY_SIZE(addrList);
390
391 std::vector<std::string> ifaceList;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400392 if (pj_enum_ip_interface(pj_AF_UNSPEC(), &addrCnt, addrList) == PJ_SUCCESS) {
393 for (unsigned i = 0; i < addrCnt; i++) {
394 char addr[PJ_INET6_ADDRSTRLEN];
395 pj_sockaddr_print(&addrList[i], addr, sizeof(addr), 0);
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400396 ifaceList.emplace_back(addr);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400397 }
398 }
399
400 return ifaceList;
401}
402
403std::vector<IpAddr>
404ip_utils::getLocalNameservers()
405{
406 std::vector<IpAddr> res;
407#if defined __ANDROID__ || defined _WIN32 || TARGET_OS_IPHONE
408#ifdef _MSC_VER
409#pragma message(__FILE__ "(" STR2(__LINE__) ") : -NOTE- " \
410 "Not implemented")
411#else
412#warning "Not implemented"
413#endif
414#else
415 if (not(_res.options & RES_INIT))
416 res_init();
417 res.insert(res.end(), _res.nsaddr_list, _res.nsaddr_list + _res.nscount);
418#endif
419 return res;
420}
421
422bool
423IpAddr::isValid(std::string_view address, pj_uint16_t family)
424{
425 const pj_str_t pjstring(sip_utils::CONST_PJ_STR(address));
426 pj_str_t ret_str;
427 pj_uint16_t ret_port;
428 int ret_family;
429 auto status = pj_sockaddr_parse2(pj_AF_UNSPEC(), 0, &pjstring, &ret_str, &ret_port, &ret_family);
430 if (status != PJ_SUCCESS || (family != pj_AF_UNSPEC() && ret_family != family))
431 return false;
432
433 char buf[PJ_INET6_ADDRSTRLEN];
434 pj_str_t addr_with_null = {buf, 0};
435 pj_strncpy_with_null(&addr_with_null, &ret_str, sizeof(buf));
436 struct sockaddr sa;
437 return inet_pton(ret_family == pj_AF_INET6() ? AF_INET6 : AF_INET, buf, &(sa.sa_data)) == 1;
438}
439
440bool
441IpAddr::isUnspecified() const
442{
443 switch (addr.addr.sa_family) {
444 case AF_INET:
445 return IN_IS_ADDR_UNSPECIFIED(&addr.ipv4.sin_addr);
446 case AF_INET6:
447 return IN6_IS_ADDR_UNSPECIFIED(reinterpret_cast<const in6_addr*>(&addr.ipv6.sin6_addr));
448 default:
449 return true;
450 }
451}
452
453bool
454IpAddr::isLoopback() const
455{
456 switch (addr.addr.sa_family) {
457 case AF_INET: {
458 auto addr_host = ntohl(addr.ipv4.sin_addr.s_addr);
459 uint8_t b1 = (uint8_t)(addr_host >> 24);
460 return b1 == 127;
461 }
462 case AF_INET6:
463 return IN6_IS_ADDR_LOOPBACK(reinterpret_cast<const in6_addr*>(&addr.ipv6.sin6_addr));
464 default:
465 return false;
466 }
467}
468
469bool
470IpAddr::isPrivate() const
471{
472 if (isLoopback()) {
473 return true;
474 }
475 switch (addr.addr.sa_family) {
476 case AF_INET: {
477 auto addr_host = ntohl(addr.ipv4.sin_addr.s_addr);
478 uint8_t b1, b2;
479 b1 = (uint8_t)(addr_host >> 24);
480 b2 = (uint8_t)((addr_host >> 16) & 0x0ff);
481 // 10.x.y.z
482 if (b1 == 10)
483 return true;
484 // 172.16.0.0 - 172.31.255.255
485 if ((b1 == 172) && (b2 >= 16) && (b2 <= 31))
486 return true;
487 // 192.168.0.0 - 192.168.255.255
488 if ((b1 == 192) && (b2 == 168))
489 return true;
490 return false;
491 }
492 case AF_INET6: {
493 const pj_uint8_t* addr6 = reinterpret_cast<const pj_uint8_t*>(&addr.ipv6.sin6_addr);
494 if (addr6[0] == 0xfc)
495 return true;
496 return false;
497 }
498 default:
499 return false;
500 }
501}
Sébastien Blin464bdff2023-07-19 08:02:53 -0400502} // namespace dhtnet