ip_helper_generic.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. /*
  2. * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
  3. * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. */
  19. #include <pj/ip_helper.h>
  20. #include <pj/addr_resolv.h>
  21. #include <pj/assert.h>
  22. #include <pj/errno.h>
  23. #include <pj/string.h>
  24. #include <pj/compat/socket.h>
  25. #include <pj/sock.h>
  26. #if defined(PJ_LINUX) && PJ_LINUX!=0
  27. /* The following headers are used to get DEPRECATED addresses */
  28. #include <arpa/inet.h>
  29. #include <asm/types.h>
  30. #include <linux/netlink.h>
  31. #include <linux/rtnetlink.h>
  32. #include <sys/socket.h>
  33. #include <unistd.h>
  34. #endif
  35. /* Set to 1 to enable tracing */
  36. #if 0
  37. # include <pj/log.h>
  38. # define THIS_FILE "ip_helper_generic.c"
  39. # define TRACE_(exp) PJ_LOG(5,exp)
  40. static const char *get_os_errmsg(void)
  41. {
  42. static char errmsg[PJ_ERR_MSG_SIZE];
  43. pj_strerror(pj_get_os_error(), errmsg, sizeof(errmsg));
  44. return errmsg;
  45. }
  46. static const char *get_addr(void *addr)
  47. {
  48. static char txt[PJ_INET6_ADDRSTRLEN];
  49. struct sockaddr *ad = (struct sockaddr*)addr;
  50. if (ad->sa_family != PJ_AF_INET && ad->sa_family != PJ_AF_INET6)
  51. return "?";
  52. return pj_inet_ntop2(ad->sa_family, pj_sockaddr_get_addr(ad),
  53. txt, sizeof(txt));
  54. }
  55. #else
  56. # define TRACE_(exp)
  57. #endif
  58. #if 0
  59. /* dummy */
  60. #elif defined(PJ_HAS_IFADDRS_H) && PJ_HAS_IFADDRS_H != 0 && \
  61. defined(PJ_HAS_NET_IF_H) && PJ_HAS_NET_IF_H != 0
  62. /* Using getifaddrs() is preferred since it can work with both IPv4 and IPv6 */
  63. static pj_status_t if_enum_by_af(int af,
  64. unsigned *p_cnt,
  65. pj_sockaddr ifs[])
  66. {
  67. struct ifaddrs *ifap = NULL, *it;
  68. unsigned max;
  69. PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
  70. TRACE_((THIS_FILE, "Starting interface enum with getifaddrs() for af=%d",
  71. af));
  72. if (getifaddrs(&ifap) != 0) {
  73. TRACE_((THIS_FILE, " getifarrds() failed: %s", get_os_errmsg()));
  74. return PJ_RETURN_OS_ERROR(pj_get_netos_error());
  75. }
  76. it = ifap;
  77. max = *p_cnt;
  78. *p_cnt = 0;
  79. for (; it!=NULL && *p_cnt < max; it = it->ifa_next) {
  80. struct sockaddr *ad = it->ifa_addr;
  81. TRACE_((THIS_FILE, " checking %s", it->ifa_name));
  82. if ((it->ifa_flags & IFF_UP)==0) {
  83. TRACE_((THIS_FILE, " interface is down"));
  84. continue; /* Skip when interface is down */
  85. }
  86. if ((it->ifa_flags & IFF_RUNNING)==0) {
  87. TRACE_((THIS_FILE, " interface is not running"));
  88. continue; /* Skip when interface is not running */
  89. }
  90. #if PJ_IP_HELPER_IGNORE_LOOPBACK_IF
  91. if (it->ifa_flags & IFF_LOOPBACK) {
  92. TRACE_((THIS_FILE, " loopback interface"));
  93. continue; /* Skip loopback interface */
  94. }
  95. #endif
  96. if (ad==NULL) {
  97. TRACE_((THIS_FILE, " NULL address ignored"));
  98. continue; /* reported to happen on Linux 2.6.25.9
  99. with ppp interface */
  100. }
  101. if (ad->sa_family != af) {
  102. TRACE_((THIS_FILE, " address %s ignored (af=%d)",
  103. get_addr(ad), ad->sa_family));
  104. continue; /* Skip when interface is down */
  105. }
  106. /* Ignore 192.0.0.0/29 address.
  107. * Ref: https://datatracker.ietf.org/doc/html/rfc7335#section-4
  108. */
  109. if (af==pj_AF_INET() &&
  110. (pj_ntohl(((pj_sockaddr_in*)ad)->sin_addr.s_addr) >> 4) ==
  111. 201326592) /* 0b1100000000000000000000000000 which is
  112. 192.0.0.0 >> 4 */
  113. {
  114. TRACE_((THIS_FILE, " address %s ignored (192.0.0.0/29 class)",
  115. get_addr(ad), ad->sa_family));
  116. continue;
  117. }
  118. /* Ignore 0.0.0.0/8 address. This is a special address
  119. * which doesn't seem to have practical use.
  120. */
  121. if (af==pj_AF_INET() &&
  122. (pj_ntohl(((pj_sockaddr_in*)ad)->sin_addr.s_addr) >> 24) == 0)
  123. {
  124. TRACE_((THIS_FILE, " address %s ignored (0.0.0.0/8 class)",
  125. get_addr(ad), ad->sa_family));
  126. continue;
  127. }
  128. TRACE_((THIS_FILE, " address %s (af=%d) added at index %d",
  129. get_addr(ad), ad->sa_family, *p_cnt));
  130. pj_bzero(&ifs[*p_cnt], sizeof(ifs[0]));
  131. pj_memcpy(&ifs[*p_cnt], ad, pj_sockaddr_get_len(ad));
  132. PJ_SOCKADDR_RESET_LEN(&ifs[*p_cnt]);
  133. (*p_cnt)++;
  134. }
  135. freeifaddrs(ifap);
  136. TRACE_((THIS_FILE, "done, found %d address(es)", *p_cnt));
  137. return (*p_cnt != 0) ? PJ_SUCCESS : PJ_ENOTFOUND;
  138. }
  139. #elif defined(SIOCGIFCONF) && \
  140. defined(PJ_HAS_NET_IF_H) && PJ_HAS_NET_IF_H != 0
  141. /* Note: this does not work with IPv6 */
  142. static pj_status_t if_enum_by_af(int af,
  143. unsigned *p_cnt,
  144. pj_sockaddr ifs[])
  145. {
  146. pj_sock_t sock;
  147. char buf[512];
  148. struct ifconf ifc;
  149. struct ifreq *ifr;
  150. int i, count;
  151. pj_status_t status;
  152. PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
  153. TRACE_((THIS_FILE, "Starting interface enum with SIOCGIFCONF for af=%d",
  154. af));
  155. status = pj_sock_socket(af, PJ_SOCK_DGRAM, 0, &sock);
  156. if (status != PJ_SUCCESS)
  157. return status;
  158. /* Query available interfaces */
  159. ifc.ifc_len = sizeof(buf);
  160. ifc.ifc_buf = buf;
  161. if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
  162. int oserr = pj_get_netos_error();
  163. TRACE_((THIS_FILE, " ioctl(SIOCGIFCONF) failed: %s", get_os_errmsg()));
  164. pj_sock_close(sock);
  165. return PJ_RETURN_OS_ERROR(oserr);
  166. }
  167. /* Interface interfaces */
  168. ifr = (struct ifreq*) ifc.ifc_req;
  169. count = ifc.ifc_len / sizeof(struct ifreq);
  170. if (count > *p_cnt)
  171. count = *p_cnt;
  172. *p_cnt = 0;
  173. for (i=0; i<count; ++i) {
  174. struct ifreq *itf = &ifr[i];
  175. struct ifreq iff = *itf;
  176. struct sockaddr *ad = &itf->ifr_addr;
  177. TRACE_((THIS_FILE, " checking interface %s", itf->ifr_name));
  178. /* Skip address with different family */
  179. if (ad->sa_family != af) {
  180. TRACE_((THIS_FILE, " address %s (af=%d) ignored",
  181. get_addr(ad), (int)ad->sa_family));
  182. continue;
  183. }
  184. if (ioctl(sock, SIOCGIFFLAGS, &iff) != 0) {
  185. TRACE_((THIS_FILE, " ioctl(SIOCGIFFLAGS) failed: %s",
  186. get_os_errmsg()));
  187. continue; /* Failed to get flags, continue */
  188. }
  189. if ((iff.ifr_flags & IFF_UP)==0) {
  190. TRACE_((THIS_FILE, " interface is down"));
  191. continue; /* Skip when interface is down */
  192. }
  193. if ((iff.ifr_flags & IFF_RUNNING)==0) {
  194. TRACE_((THIS_FILE, " interface is not running"));
  195. continue; /* Skip when interface is not running */
  196. }
  197. #if PJ_IP_HELPER_IGNORE_LOOPBACK_IF
  198. if (iff.ifr_flags & IFF_LOOPBACK) {
  199. TRACE_((THIS_FILE, " loopback interface"));
  200. continue; /* Skip loopback interface */
  201. }
  202. #endif
  203. /* Ignore 192.0.0.0/29 address.
  204. * Ref: https://datatracker.ietf.org/doc/html/rfc7335#section-4
  205. */
  206. if (af==pj_AF_INET() &&
  207. (pj_ntohl(((pj_sockaddr_in*)ad)->sin_addr.s_addr) >> 4) ==
  208. 201326592) /* 0b1100000000000000000000000000 which is
  209. 192.0.0.0 >> 4 */
  210. {
  211. TRACE_((THIS_FILE, " address %s ignored (192.0.0.0/29 class)",
  212. get_addr(ad), ad->sa_family));
  213. continue;
  214. }
  215. /* Ignore 0.0.0.0/8 address. This is a special address
  216. * which doesn't seem to have practical use.
  217. */
  218. if (af==pj_AF_INET() &&
  219. (pj_ntohl(((pj_sockaddr_in*)ad)->sin_addr.s_addr) >> 24) == 0)
  220. {
  221. TRACE_((THIS_FILE, " address %s ignored (0.0.0.0/8 class)",
  222. get_addr(ad), ad->sa_family));
  223. continue;
  224. }
  225. TRACE_((THIS_FILE, " address %s (af=%d) added at index %d",
  226. get_addr(ad), ad->sa_family, *p_cnt));
  227. pj_bzero(&ifs[*p_cnt], sizeof(ifs[0]));
  228. pj_memcpy(&ifs[*p_cnt], ad, pj_sockaddr_get_len(ad));
  229. PJ_SOCKADDR_RESET_LEN(&ifs[*p_cnt]);
  230. (*p_cnt)++;
  231. }
  232. /* Done with socket */
  233. pj_sock_close(sock);
  234. TRACE_((THIS_FILE, "done, found %d address(es)", *p_cnt));
  235. return (*p_cnt != 0) ? PJ_SUCCESS : PJ_ENOTFOUND;
  236. }
  237. #elif defined(PJ_HAS_NET_IF_H) && PJ_HAS_NET_IF_H != 0
  238. /* Note: this does not work with IPv6 */
  239. static pj_status_t if_enum_by_af(int af, unsigned *p_cnt, pj_sockaddr ifs[])
  240. {
  241. struct if_nameindex *if_list;
  242. struct ifreq ifreq;
  243. pj_sock_t sock;
  244. unsigned i, max_count;
  245. pj_status_t status;
  246. PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
  247. TRACE_((THIS_FILE, "Starting if_nameindex() for af=%d", af));
  248. status = pj_sock_socket(af, PJ_SOCK_DGRAM, 0, &sock);
  249. if (status != PJ_SUCCESS)
  250. return status;
  251. if_list = if_nameindex();
  252. if (if_list == NULL)
  253. return PJ_ENOTFOUND;
  254. max_count = *p_cnt;
  255. *p_cnt = 0;
  256. for (i=0; if_list[i].if_index && *p_cnt<max_count; ++i) {
  257. struct sockaddr *ad;
  258. int rc;
  259. pj_ansi_strxcpy(ifreq.ifr_name, if_list[i].if_name, IFNAMSIZ);
  260. TRACE_((THIS_FILE, " checking interface %s", ifreq.ifr_name));
  261. if ((rc=ioctl(sock, SIOCGIFFLAGS, &ifreq)) != 0) {
  262. TRACE_((THIS_FILE, " ioctl(SIOCGIFFLAGS) failed: %s",
  263. get_os_errmsg()));
  264. continue; /* Failed to get flags, continue */
  265. }
  266. if ((ifreq.ifr_flags & IFF_UP)==0) {
  267. TRACE_((THIS_FILE, " interface is down"));
  268. continue; /* Skip when interface is down */
  269. }
  270. if ((ifreq.ifr_flags & IFF_RUNNING)==0) {
  271. TRACE_((THIS_FILE, " interface is not running"));
  272. continue; /* Skip when interface is not running */
  273. }
  274. #if PJ_IP_HELPER_IGNORE_LOOPBACK_IF
  275. if (ifreq.ifr_flags & IFF_LOOPBACK) {
  276. TRACE_((THIS_FILE, " loopback interface"));
  277. continue; /* Skip loopback interface */
  278. }
  279. #endif
  280. /* Note: SIOCGIFADDR does not work for IPv6! */
  281. if ((rc=ioctl(sock, SIOCGIFADDR, &ifreq)) != 0) {
  282. TRACE_((THIS_FILE, " ioctl(SIOCGIFADDR) failed: %s",
  283. get_os_errmsg()));
  284. continue; /* Failed to get address, continue */
  285. }
  286. ad = (struct sockaddr*) &ifreq.ifr_addr;
  287. if (ad->sa_family != af) {
  288. TRACE_((THIS_FILE, " address %s family %d ignored",
  289. get_addr(&ifreq.ifr_addr),
  290. ifreq.ifr_addr.sa_family));
  291. continue; /* Not address family that we want, continue */
  292. }
  293. /* Ignore 192.0.0.0/29 address.
  294. * Ref: https://datatracker.ietf.org/doc/html/rfc7335#section-4
  295. */
  296. if (af==pj_AF_INET() &&
  297. (pj_ntohl(((pj_sockaddr_in*)ad)->sin_addr.s_addr) >> 4) ==
  298. 201326592) /* 0b1100000000000000000000000000 which is
  299. 192.0.0.0 >> 4 */
  300. {
  301. TRACE_((THIS_FILE, " address %s ignored (192.0.0.0/29 class)",
  302. get_addr(ad), ad->sa_family));
  303. continue;
  304. }
  305. /* Ignore 0.0.0.0/8 address. This is a special address
  306. * which doesn't seem to have practical use.
  307. */
  308. if (af==pj_AF_INET() &&
  309. (pj_ntohl(((pj_sockaddr_in*)ad)->sin_addr.s_addr) >> 24) == 0)
  310. {
  311. TRACE_((THIS_FILE, " address %s ignored (0.0.0.0/8 class)",
  312. get_addr(ad), ad->sa_family));
  313. continue;
  314. }
  315. /* Got an address ! */
  316. TRACE_((THIS_FILE, " address %s (af=%d) added at index %d",
  317. get_addr(ad), ad->sa_family, *p_cnt));
  318. pj_bzero(&ifs[*p_cnt], sizeof(ifs[0]));
  319. pj_memcpy(&ifs[*p_cnt], ad, pj_sockaddr_get_len(ad));
  320. PJ_SOCKADDR_RESET_LEN(&ifs[*p_cnt]);
  321. (*p_cnt)++;
  322. }
  323. if_freenameindex(if_list);
  324. pj_sock_close(sock);
  325. TRACE_((THIS_FILE, "done, found %d address(es)", *p_cnt));
  326. return (*p_cnt != 0) ? PJ_SUCCESS : PJ_ENOTFOUND;
  327. }
  328. #else
  329. static pj_status_t if_enum_by_af(int af,
  330. unsigned *p_cnt,
  331. pj_sockaddr ifs[])
  332. {
  333. pj_status_t status;
  334. PJ_ASSERT_RETURN(p_cnt && *p_cnt > 0 && ifs, PJ_EINVAL);
  335. pj_bzero(ifs, sizeof(ifs[0]) * (*p_cnt));
  336. /* Just get one default route */
  337. status = pj_getdefaultipinterface(af, &ifs[0]);
  338. if (status != PJ_SUCCESS)
  339. return status;
  340. *p_cnt = 1;
  341. return PJ_SUCCESS;
  342. }
  343. #endif /* SIOCGIFCONF */
  344. /*
  345. * Enumerate the local IP interface currently active in the host.
  346. */
  347. PJ_DEF(pj_status_t) pj_enum_ip_interface(int af,
  348. unsigned *p_cnt,
  349. pj_sockaddr ifs[])
  350. {
  351. unsigned start;
  352. pj_status_t status;
  353. PJ_ASSERT_RETURN(p_cnt && *p_cnt > 0 && ifs, PJ_EINVAL);
  354. pj_bzero(ifs, sizeof(ifs[0]) * (*p_cnt));
  355. start = 0;
  356. if (af==PJ_AF_INET6 || af==PJ_AF_UNSPEC) {
  357. unsigned max = *p_cnt;
  358. status = if_enum_by_af(PJ_AF_INET6, &max, &ifs[start]);
  359. if (status == PJ_SUCCESS) {
  360. start += max;
  361. (*p_cnt) -= max;
  362. }
  363. }
  364. if (af==PJ_AF_INET || af==PJ_AF_UNSPEC) {
  365. unsigned max = *p_cnt;
  366. status = if_enum_by_af(PJ_AF_INET, &max, &ifs[start]);
  367. if (status == PJ_SUCCESS) {
  368. start += max;
  369. (*p_cnt) -= max;
  370. }
  371. }
  372. *p_cnt = start;
  373. return (*p_cnt != 0) ? PJ_SUCCESS : PJ_ENOTFOUND;
  374. }
  375. /*
  376. * Enumerate the IP routing table for this host.
  377. */
  378. PJ_DEF(pj_status_t) pj_enum_ip_route(unsigned *p_cnt,
  379. pj_ip_route_entry routes[])
  380. {
  381. pj_sockaddr itf;
  382. pj_status_t status;
  383. PJ_ASSERT_RETURN(p_cnt && *p_cnt > 0 && routes, PJ_EINVAL);
  384. pj_bzero(routes, sizeof(routes[0]) * (*p_cnt));
  385. /* Just get one default route */
  386. status = pj_getdefaultipinterface(PJ_AF_INET, &itf);
  387. if (status != PJ_SUCCESS)
  388. return status;
  389. routes[0].ipv4.if_addr.s_addr = itf.ipv4.sin_addr.s_addr;
  390. routes[0].ipv4.dst_addr.s_addr = 0;
  391. routes[0].ipv4.mask.s_addr = 0;
  392. *p_cnt = 1;
  393. return PJ_SUCCESS;
  394. }
  395. #if defined(PJ_LINUX) && PJ_LINUX!=0
  396. static pj_status_t get_ipv6_deprecated(unsigned *count, pj_sockaddr addr[])
  397. {
  398. struct {
  399. struct nlmsghdr nlmsg_info;
  400. struct ifaddrmsg ifaddrmsg_info;
  401. } netlink_req;
  402. long pagesize = sysconf(_SC_PAGESIZE);
  403. if (pagesize <= 0)
  404. pagesize = 4096; /* Assume pagesize is 4096 if sysconf() failed */
  405. int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  406. if (fd < 0)
  407. return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
  408. bzero(&netlink_req, sizeof(netlink_req));
  409. netlink_req.nlmsg_info.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
  410. netlink_req.nlmsg_info.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
  411. netlink_req.nlmsg_info.nlmsg_type = RTM_GETADDR;
  412. netlink_req.nlmsg_info.nlmsg_pid = getpid();
  413. netlink_req.ifaddrmsg_info.ifa_family = AF_INET6;
  414. int rtn = send(fd, &netlink_req, netlink_req.nlmsg_info.nlmsg_len, 0);
  415. if (rtn < 0) {
  416. close(fd);
  417. return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
  418. }
  419. char read_buffer[pagesize];
  420. size_t idx = 0;
  421. while(1) {
  422. bzero(read_buffer, pagesize);
  423. int read_size = recv(fd, read_buffer, pagesize, 0);
  424. if (read_size < 0) {
  425. close(fd);
  426. return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
  427. }
  428. struct nlmsghdr *nlmsg_ptr = (struct nlmsghdr *) read_buffer;
  429. int nlmsg_len = read_size;
  430. if (nlmsg_len < (int)sizeof (struct nlmsghdr)) {
  431. close(fd);
  432. return PJ_ETOOSMALL;
  433. }
  434. for(; NLMSG_OK(nlmsg_ptr, nlmsg_len);
  435. nlmsg_ptr = NLMSG_NEXT(nlmsg_ptr, nlmsg_len))
  436. {
  437. if (nlmsg_ptr->nlmsg_type == NLMSG_DONE)
  438. goto on_return;
  439. struct ifaddrmsg *ifaddrmsg_ptr;
  440. struct rtattr *rtattr_ptr;
  441. int ifaddrmsg_len;
  442. ifaddrmsg_ptr = (struct ifaddrmsg*)NLMSG_DATA(nlmsg_ptr);
  443. if (ifaddrmsg_ptr->ifa_flags & IFA_F_DEPRECATED ||
  444. ifaddrmsg_ptr->ifa_flags & IFA_F_TENTATIVE)
  445. {
  446. rtattr_ptr = (struct rtattr*)IFA_RTA(ifaddrmsg_ptr);
  447. ifaddrmsg_len = IFA_PAYLOAD(nlmsg_ptr);
  448. for(;RTA_OK(rtattr_ptr, ifaddrmsg_len);
  449. rtattr_ptr = RTA_NEXT(rtattr_ptr, ifaddrmsg_len))
  450. {
  451. switch(rtattr_ptr->rta_type) {
  452. case IFA_ADDRESS:
  453. // Check if addr can contains more data
  454. if (idx >= *count)
  455. break;
  456. // Store deprecated IP
  457. char deprecatedAddr[PJ_INET6_ADDRSTRLEN];
  458. inet_ntop(ifaddrmsg_ptr->ifa_family,
  459. RTA_DATA(rtattr_ptr),
  460. deprecatedAddr,
  461. sizeof(deprecatedAddr));
  462. pj_str_t pj_addr_str;
  463. pj_cstr(&pj_addr_str, deprecatedAddr);
  464. pj_sockaddr_init(pj_AF_INET6(), &addr[idx],
  465. &pj_addr_str, 0);
  466. ++idx;
  467. break;
  468. default:
  469. break;
  470. }
  471. }
  472. }
  473. }
  474. }
  475. on_return:
  476. close(fd);
  477. *count = idx;
  478. return PJ_SUCCESS;
  479. }
  480. #endif
  481. /*
  482. * Enumerate the local IP interface currently active in the host.
  483. */
  484. PJ_DEF(pj_status_t) pj_enum_ip_interface2( const pj_enum_ip_option *opt,
  485. unsigned *p_cnt,
  486. pj_sockaddr ifs[])
  487. {
  488. pj_enum_ip_option opt_;
  489. if (opt)
  490. opt_ = *opt;
  491. else
  492. pj_enum_ip_option_default(&opt_);
  493. if (opt_.af != pj_AF_INET() && opt_.omit_deprecated_ipv6) {
  494. #if defined(PJ_LINUX) && PJ_LINUX!=0
  495. pj_sockaddr addrs[*p_cnt];
  496. pj_sockaddr deprecatedAddrs[*p_cnt];
  497. unsigned deprecatedCount = *p_cnt;
  498. unsigned cnt = 0;
  499. unsigned i;
  500. pj_status_t status;
  501. status = get_ipv6_deprecated(&deprecatedCount, deprecatedAddrs);
  502. if (status != PJ_SUCCESS)
  503. return status;
  504. status = pj_enum_ip_interface(opt_.af, p_cnt, addrs);
  505. if (status != PJ_SUCCESS)
  506. return status;
  507. for (i = 0; i < *p_cnt; ++i) {
  508. unsigned j;
  509. ifs[cnt++] = addrs[i];
  510. if (addrs[i].addr.sa_family != pj_AF_INET6())
  511. continue;
  512. for (j = 0; j < deprecatedCount; ++j) {
  513. if (pj_sockaddr_cmp(&addrs[i], &deprecatedAddrs[j]) == 0) {
  514. cnt--;
  515. break;
  516. }
  517. }
  518. }
  519. *p_cnt = cnt;
  520. return *p_cnt ? PJ_SUCCESS : PJ_ENOTFOUND;
  521. #else
  522. return PJ_ENOTSUP;
  523. #endif
  524. }
  525. return pj_enum_ip_interface(opt_.af, p_cnt, ifs);
  526. }