blob: 9cd5c0f47c3fe8f6df3149a8433c3ab9e7392b30 [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 } else {
93 return {};
94 }
95 } else {
96 return {};
Adrien Béraud612b55b2023-05-29 10:42:04 -040097 }
98#elif (defined(BSD) && BSD >= 199306) || defined(__FreeBSD_kernel__)
Adrien Béraud612b55b2023-05-29 10:42:04 -040099 struct ifaddrs* ifap;
100 struct ifaddrs* ifa;
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400101 if (getifaddrs(&ifap) != 0) {
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400102 return {};
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400103 }
Adrien Béraud612b55b2023-05-29 10:42:04 -0400104 // Cycle through available interfaces.
105 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
106 // Skip loopback, point-to-point and down interfaces.
107 // except don't skip down interfaces if we're trying to get
108 // a list of configurable interfaces.
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400109 if ((ifa->ifa_flags & IFF_LOOPBACK) || (!(ifa->ifa_flags & IFF_UP))) {
Adrien Béraud612b55b2023-05-29 10:42:04 -0400110 continue;
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400111 }
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400112 auto family = ifa->ifa_addr->sa_family;
113 if (family == AF_INET) {
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400114 void* addr = &((struct sockaddr_in*)ifa->ifa_addr)->sin_addr;
115 if (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
116 continue;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400117 }
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400118 ret.interface = ifa->ifa_name;
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400119 p = inet_ntop(family, addr, tempstr, sizeof(tempstr));
120 if (p) {
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400121 ret.address = p;
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400122 }
Adrien Béraud612b55b2023-05-29 10:42:04 -0400123 break;
124 }
125 }
126 freeifaddrs(ifap);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400127#else
128 struct ifconf ifConf;
129 struct ifreq ifReq;
130 struct sockaddr_in localAddr;
131 char szBuffer[MAX_INTERFACE * sizeof(struct ifreq)];
132 int nResult;
133 int localSock;
134 memset(&ifConf, 0, sizeof(ifConf));
135 memset(&ifReq, 0, sizeof(ifReq));
136 memset(szBuffer, 0, sizeof(szBuffer));
137 memset(&localAddr, 0, sizeof(localAddr));
138 // Create an unbound datagram socket to do the SIOCGIFADDR ioctl on.
139 localSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400140 if (localSock == INVALID_SOCKET) {
141 return {};
142 }
Adrien Béraud612b55b2023-05-29 10:42:04 -0400143 /* Get the interface configuration information... */
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400144 ifConf.ifc_len = sizeof(szBuffer);
145 ifConf.ifc_buf = (caddr_t)szBuffer;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400146 nResult = ioctl(localSock, SIOCGIFCONF, &ifConf);
147 if (nResult < 0) {
148 close(localSock);
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400149 return {};
Adrien Béraud612b55b2023-05-29 10:42:04 -0400150 }
151 unsigned int i;
152 unsigned int j = 0;
153 // Cycle through the list of interfaces looking for IP addresses.
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400154 for (i = 0u; i < ifConf.ifc_len && j < MIN_INTERFACE;) {
155 struct ifreq* pifReq = (struct ifreq*)((caddr_t)ifConf.ifc_req + i);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400156 i += sizeof *pifReq;
157 // See if this is the sort of interface we want to deal with.
158 memset(ifReq.ifr_name, 0, sizeof(ifReq.ifr_name));
159 strncpy(ifReq.ifr_name, pifReq->ifr_name, sizeof(ifReq.ifr_name));
160 ioctl(localSock, SIOCGIFFLAGS, &ifReq);
161 // Skip loopback, point-to-point and down interfaces.
162 // except don't skip down interfaces if we're trying to get
163 // a list of configurable interfaces.
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400164 if ((ifReq.ifr_flags & IFF_LOOPBACK) || (!(ifReq.ifr_flags & IFF_UP))) {
Adrien Béraud612b55b2023-05-29 10:42:04 -0400165 continue;
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400166 }
Adrien Béraud612b55b2023-05-29 10:42:04 -0400167 if (pifReq->ifr_addr.sa_family == AF_INET) {
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400168 if (((sockaddr_in*)&pifReq->ifr_addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
Adrien Béraud612b55b2023-05-29 10:42:04 -0400169 // We don't want the loopback interface. Go to the next one.
170 continue;
171 }
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400172 ret.interface = pifReq->ifr_name;
173 p = inet_ntop(pifReq->ifr_addr.sa_family,
Adrien Beraud64bb00f2023-08-23 19:06:46 -0400174 &((sockaddr_in*)&pifReq->ifr_addr)->sin_addr,
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400175 tempstr,
176 sizeof(tempstr));
177 if (p)
178 ret.address = p;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400179 }
180 j++; // Increment j if we found an address which is not loopback and is up.
181 }
182 close(localSock);
Andreas Traczyk24cc01e2023-08-23 18:55:15 -0400183 if (p == NULL) {
184 return {};
185 }
Adrien Béraud612b55b2023-05-29 10:42:04 -0400186#endif
Adrien Beraud64bb00f2023-08-23 19:06:46 -0400187 return ret;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400188}
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400189
Adrien Béraud612b55b2023-05-29 10:42:04 -0400190std::string
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400191ip_utils::getGateway(std::string_view localHost, ip_utils::subnet_mask prefix)
Adrien Béraud612b55b2023-05-29 10:42:04 -0400192{
Adrien Béraud612b55b2023-05-29 10:42:04 -0400193 if (prefix == ip_utils::subnet_mask::prefix_32bit)
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400194 return std::string(localHost);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400195 std::string defaultGw {};
196 // Make a vector of each individual number in the ip address.
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400197 std::vector<std::string_view> tokens = split_string(localHost, '.');
Adrien Béraud612b55b2023-05-29 10:42:04 -0400198 // Build a gateway address from the individual ip components.
199 for (unsigned i = 0; i <= (unsigned) prefix; i++)
Adrien Béraud80c14e12023-07-18 16:13:15 -0400200 defaultGw = fmt::format("{:s}{:s}.", defaultGw, tokens[i]);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400201 for (unsigned i = (unsigned) ip_utils::subnet_mask::prefix_32bit;
202 i > (unsigned) prefix + 1;
203 i--)
204 defaultGw += "0.";
205 defaultGw += "1";
206 return defaultGw;
207}
208
209IpAddr
210ip_utils::getLocalGateway()
211{
212 char localHostBuf[INET_ADDRSTRLEN];
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400213 auto hostInfo = ip_utils::getHostName();
214 if (hostInfo.address.empty()) {
Morteza Namvar5f639522023-07-04 17:08:58 -0400215 // JAMI_WARN("Couldn't find local host");
Adrien Béraud612b55b2023-05-29 10:42:04 -0400216 return {};
217 } else {
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400218 return IpAddr(ip_utils::getGateway(hostInfo.address, ip_utils::subnet_mask::prefix_24bit));
Adrien Béraud612b55b2023-05-29 10:42:04 -0400219 }
220}
221
222std::vector<IpAddr>
223ip_utils::getAddrList(std::string_view name, pj_uint16_t family)
224{
225 std::vector<IpAddr> ipList;
226 if (name.empty())
227 return ipList;
228 if (IpAddr::isValid(name, family)) {
229 ipList.emplace_back(name);
230 return ipList;
231 }
232
233 static constexpr unsigned MAX_ADDR_NUM = 128;
234 pj_addrinfo res[MAX_ADDR_NUM];
235 unsigned addr_num = MAX_ADDR_NUM;
236 const pj_str_t pjname(sip_utils::CONST_PJ_STR(name));
237 auto status = pj_getaddrinfo(family, &pjname, &addr_num, res);
238 if (status != PJ_SUCCESS) {
Morteza Namvar5f639522023-07-04 17:08:58 -0400239 // JAMI_ERR("Error resolving %.*s : %s",
240 // (int) name.size(),
241 // name.data(),
242 // sip_utils::sip_strerror(status).c_str());
Adrien Béraud612b55b2023-05-29 10:42:04 -0400243 return ipList;
244 }
245
246 for (unsigned i = 0; i < addr_num; i++) {
247 bool found = false;
248 for (const auto& ip : ipList)
249 if (!pj_sockaddr_cmp(&ip, &res[i].ai_addr)) {
250 found = true;
251 break;
252 }
253 if (!found)
254 ipList.emplace_back(res[i].ai_addr);
255 }
256
257 return ipList;
258}
259
260bool
261ip_utils::haveCommonAddr(const std::vector<IpAddr>& a, const std::vector<IpAddr>& b)
262{
263 for (const auto& i : a) {
264 for (const auto& j : b) {
265 if (i == j)
266 return true;
267 }
268 }
269 return false;
270}
271
272IpAddr
273ip_utils::getLocalAddr(pj_uint16_t family)
274{
275 IpAddr ip_addr {};
276 pj_status_t 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_WARN("Could not get preferred address familly (%s)",
281 // (family == pj_AF_INET6()) ? "IPv6" : "IPv4");
Adrien Béraud612b55b2023-05-29 10:42:04 -0400282 family = (family == pj_AF_INET()) ? pj_AF_INET6() : pj_AF_INET();
283 status = pj_gethostip(family, ip_addr.pjPtr());
284 if (status == PJ_SUCCESS) {
285 return ip_addr;
286 }
Morteza Namvar5f639522023-07-04 17:08:58 -0400287 // JAMI_ERR("Could not get local IP");
Adrien Béraud612b55b2023-05-29 10:42:04 -0400288 return ip_addr;
289}
290
291IpAddr
292ip_utils::getInterfaceAddr(const std::string& interface, pj_uint16_t family)
293{
294 if (interface == DEFAULT_INTERFACE)
295 return getLocalAddr(family);
296
297 IpAddr addr {};
298
299#ifndef _WIN32
300 const auto unix_family = family == pj_AF_INET() ? AF_INET : AF_INET6;
301
302 int fd = socket(unix_family, SOCK_DGRAM, 0);
303 if (fd < 0) {
Morteza Namvar5f639522023-07-04 17:08:58 -0400304 // JAMI_ERR("Could not open socket: %m");
Adrien Béraud612b55b2023-05-29 10:42:04 -0400305 return addr;
306 }
307
308 if (unix_family == AF_INET6) {
309 int val = family != pj_AF_UNSPEC();
310 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*) &val, sizeof(val)) < 0) {
Morteza Namvar5f639522023-07-04 17:08:58 -0400311 // JAMI_ERR("Could not setsockopt: %m");
Adrien Béraud612b55b2023-05-29 10:42:04 -0400312 close(fd);
313 return addr;
314 }
315 }
316
317 ifreq ifr;
318 strncpy(ifr.ifr_name, interface.c_str(), sizeof ifr.ifr_name);
319 // guarantee that ifr_name is NULL-terminated
320 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
321
322 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
323 ifr.ifr_addr.sa_family = unix_family;
324
325 ioctl(fd, SIOCGIFADDR, &ifr);
326 close(fd);
327
328 addr = ifr.ifr_addr;
329 if (addr.isUnspecified())
330 return getLocalAddr(addr.getFamily());
331#else // _WIN32
332 struct addrinfo hints;
333 struct addrinfo* result = NULL;
334 struct sockaddr_in* sockaddr_ipv4;
335 struct sockaddr_in6* sockaddr_ipv6;
336
337 ZeroMemory(&hints, sizeof(hints));
338
339 DWORD dwRetval = getaddrinfo(interface.c_str(), "0", &hints, &result);
340 if (dwRetval != 0) {
Morteza Namvar5f639522023-07-04 17:08:58 -0400341 // JAMI_ERR("getaddrinfo failed with error: %lu", dwRetval);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400342 return addr;
343 }
344
345 switch (result->ai_family) {
346 sockaddr_ipv4 = (struct sockaddr_in*) result->ai_addr;
347 addr = sockaddr_ipv4->sin_addr;
348 break;
349 case AF_INET6:
350 sockaddr_ipv6 = (struct sockaddr_in6*) result->ai_addr;
351 addr = sockaddr_ipv6->sin6_addr;
352 break;
353 default:
354 break;
355 }
356
357 if (addr.isUnspecified())
358 return getLocalAddr(addr.getFamily());
359#endif // !_WIN32
360
361 return addr;
362}
363
364std::vector<std::string>
365ip_utils::getAllIpInterfaceByName()
366{
367 std::vector<std::string> ifaceList;
368 ifaceList.push_back("default");
369#ifndef _WIN32
370 static ifreq ifreqs[20];
371 ifconf ifconf;
372
373 ifconf.ifc_buf = (char*) (ifreqs);
374 ifconf.ifc_len = sizeof(ifreqs);
375
376 int sock = socket(AF_INET6, SOCK_STREAM, 0);
377
378 if (sock >= 0) {
379 if (ioctl(sock, SIOCGIFCONF, &ifconf) >= 0)
380 for (unsigned i = 0; i < ifconf.ifc_len / sizeof(ifreq); ++i)
381 ifaceList.push_back(std::string(ifreqs[i].ifr_name));
382
383 close(sock);
384 }
385
386#else
Morteza Namvar5f639522023-07-04 17:08:58 -0400387 // JAMI_ERR("Not implemented yet. (iphlpapi.h problem)");
Adrien Béraud612b55b2023-05-29 10:42:04 -0400388#endif
389 return ifaceList;
390}
391
392std::vector<std::string>
393ip_utils::getAllIpInterface()
394{
395 pj_sockaddr addrList[16];
396 unsigned addrCnt = PJ_ARRAY_SIZE(addrList);
397
398 std::vector<std::string> ifaceList;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400399 if (pj_enum_ip_interface(pj_AF_UNSPEC(), &addrCnt, addrList) == PJ_SUCCESS) {
400 for (unsigned i = 0; i < addrCnt; i++) {
401 char addr[PJ_INET6_ADDRSTRLEN];
402 pj_sockaddr_print(&addrList[i], addr, sizeof(addr), 0);
Adrien Béraud63a1fac2023-08-23 09:31:17 -0400403 ifaceList.emplace_back(addr);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400404 }
405 }
406
407 return ifaceList;
408}
409
410std::vector<IpAddr>
411ip_utils::getLocalNameservers()
412{
413 std::vector<IpAddr> res;
414#if defined __ANDROID__ || defined _WIN32 || TARGET_OS_IPHONE
415#ifdef _MSC_VER
416#pragma message(__FILE__ "(" STR2(__LINE__) ") : -NOTE- " \
417 "Not implemented")
418#else
419#warning "Not implemented"
420#endif
421#else
422 if (not(_res.options & RES_INIT))
423 res_init();
424 res.insert(res.end(), _res.nsaddr_list, _res.nsaddr_list + _res.nscount);
425#endif
426 return res;
427}
428
429bool
430IpAddr::isValid(std::string_view address, pj_uint16_t family)
431{
432 const pj_str_t pjstring(sip_utils::CONST_PJ_STR(address));
433 pj_str_t ret_str;
434 pj_uint16_t ret_port;
435 int ret_family;
436 auto status = pj_sockaddr_parse2(pj_AF_UNSPEC(), 0, &pjstring, &ret_str, &ret_port, &ret_family);
437 if (status != PJ_SUCCESS || (family != pj_AF_UNSPEC() && ret_family != family))
438 return false;
439
440 char buf[PJ_INET6_ADDRSTRLEN];
441 pj_str_t addr_with_null = {buf, 0};
442 pj_strncpy_with_null(&addr_with_null, &ret_str, sizeof(buf));
443 struct sockaddr sa;
444 return inet_pton(ret_family == pj_AF_INET6() ? AF_INET6 : AF_INET, buf, &(sa.sa_data)) == 1;
445}
446
447bool
448IpAddr::isUnspecified() const
449{
450 switch (addr.addr.sa_family) {
451 case AF_INET:
452 return IN_IS_ADDR_UNSPECIFIED(&addr.ipv4.sin_addr);
453 case AF_INET6:
454 return IN6_IS_ADDR_UNSPECIFIED(reinterpret_cast<const in6_addr*>(&addr.ipv6.sin6_addr));
455 default:
456 return true;
457 }
458}
459
460bool
461IpAddr::isLoopback() const
462{
463 switch (addr.addr.sa_family) {
464 case AF_INET: {
465 auto addr_host = ntohl(addr.ipv4.sin_addr.s_addr);
466 uint8_t b1 = (uint8_t)(addr_host >> 24);
467 return b1 == 127;
468 }
469 case AF_INET6:
470 return IN6_IS_ADDR_LOOPBACK(reinterpret_cast<const in6_addr*>(&addr.ipv6.sin6_addr));
471 default:
472 return false;
473 }
474}
475
476bool
477IpAddr::isPrivate() const
478{
479 if (isLoopback()) {
480 return true;
481 }
482 switch (addr.addr.sa_family) {
483 case AF_INET: {
484 auto addr_host = ntohl(addr.ipv4.sin_addr.s_addr);
485 uint8_t b1, b2;
486 b1 = (uint8_t)(addr_host >> 24);
487 b2 = (uint8_t)((addr_host >> 16) & 0x0ff);
488 // 10.x.y.z
489 if (b1 == 10)
490 return true;
491 // 172.16.0.0 - 172.31.255.255
492 if ((b1 == 172) && (b2 >= 16) && (b2 <= 31))
493 return true;
494 // 192.168.0.0 - 192.168.255.255
495 if ((b1 == 192) && (b2 == 168))
496 return true;
497 return false;
498 }
499 case AF_INET6: {
500 const pj_uint8_t* addr6 = reinterpret_cast<const pj_uint8_t*>(&addr.ipv6.sin6_addr);
501 if (addr6[0] == 0xfc)
502 return true;
503 return false;
504 }
505 default:
506 return false;
507 }
508}
Sébastien Blin464bdff2023-07-19 08:02:53 -0400509} // namespace dhtnet