PageRenderTime 28ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/libc/net/getnameinfo.c

http://www.minix3.org/
C | 638 lines | 464 code | 64 blank | 110 comment | 114 complexity | 45ba0edd18fdb900ee14f047c45acc89 MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  1. /* $NetBSD: getnameinfo.c,v 1.59 2015/09/22 16:15:08 christos Exp $ */
  2. /* $KAME: getnameinfo.c,v 1.45 2000/09/25 22:43:56 itojun Exp $ */
  3. /*
  4. * Copyright (c) 2000 Ben Harris.
  5. * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  6. * All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. Neither the name of the project nor the names of its contributors
  17. * may be used to endorse or promote products derived from this software
  18. * without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  21. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23. * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
  24. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. */
  32. /*
  33. * Issues to be discussed:
  34. * - Thread safe-ness must be checked
  35. * - RFC2553 says that we should raise error on short buffer. X/Open says
  36. * we need to truncate the result. We obey RFC2553 (and X/Open should be
  37. * modified). ipngwg rough consensus seems to follow RFC2553.
  38. * - What is "local" in NI_FQDN?
  39. * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other.
  40. * - (KAME extension) always attach textual scopeid (fe80::1%lo0), if
  41. * sin6_scope_id is filled - standardization status?
  42. * XXX breaks backward compat for code that expects no scopeid.
  43. * beware on merge.
  44. */
  45. #include <sys/cdefs.h>
  46. #if defined(LIBC_SCCS) && !defined(lint)
  47. __RCSID("$NetBSD: getnameinfo.c,v 1.59 2015/09/22 16:15:08 christos Exp $");
  48. #endif /* LIBC_SCCS and not lint */
  49. #ifndef RUMP_ACTION
  50. #include "namespace.h"
  51. #endif
  52. #include <sys/types.h>
  53. #include <sys/socket.h>
  54. #include <sys/un.h>
  55. #include <net/if.h>
  56. #if !defined(__minix)
  57. #include <net/if_dl.h>
  58. #include <net/if_ieee1394.h>
  59. #include <net/if_types.h>
  60. #include <netatalk/at.h>
  61. #endif /* !defined(__minix) */
  62. #include <netinet/in.h>
  63. #include <arpa/inet.h>
  64. #include <arpa/nameser.h>
  65. #include <assert.h>
  66. #include <limits.h>
  67. #include <netdb.h>
  68. #include <resolv.h>
  69. #include <stddef.h>
  70. #include <string.h>
  71. #include "servent.h"
  72. #include "hostent.h"
  73. #ifndef RUMP_ACTION
  74. #ifdef __weak_alias
  75. __weak_alias(getnameinfo,_getnameinfo)
  76. #endif
  77. #endif
  78. static const struct afd {
  79. int a_af;
  80. socklen_t a_addrlen;
  81. socklen_t a_socklen;
  82. int a_off;
  83. } afdl [] = {
  84. #ifdef INET6
  85. {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
  86. offsetof(struct sockaddr_in6, sin6_addr)},
  87. #endif
  88. {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
  89. offsetof(struct sockaddr_in, sin_addr)},
  90. {0, 0, 0, 0},
  91. };
  92. struct sockinet {
  93. u_char si_len;
  94. u_char si_family;
  95. u_short si_port;
  96. };
  97. static int getnameinfo_inet(const struct sockaddr *, socklen_t, char *,
  98. socklen_t, char *, socklen_t, int);
  99. #ifdef INET6
  100. static int ip6_parsenumeric(const struct sockaddr *, const char *, char *,
  101. socklen_t, int);
  102. static int ip6_sa2str(const struct sockaddr_in6 *, char *, size_t, int);
  103. #endif
  104. #if !defined(__minix)
  105. static int getnameinfo_atalk(const struct sockaddr *, socklen_t, char *,
  106. socklen_t, char *, socklen_t, int);
  107. static int getnameinfo_local(const struct sockaddr *, socklen_t, char *,
  108. socklen_t, char *, socklen_t, int);
  109. static int getnameinfo_link(const struct sockaddr *, socklen_t, char *,
  110. socklen_t, char *, socklen_t, int);
  111. static int hexname(const uint8_t *, size_t, char *, socklen_t);
  112. #endif /* !defined(__minix) */
  113. /*
  114. * Top-level getnameinfo() code. Look at the address family, and pick an
  115. * appropriate function to call.
  116. */
  117. int
  118. getnameinfo(const struct sockaddr *sa, socklen_t salen,
  119. char *host, socklen_t hostlen,
  120. char *serv, socklen_t servlen,
  121. int flags)
  122. {
  123. switch (sa->sa_family) {
  124. #if !defined(__minix)
  125. case AF_APPLETALK:
  126. return getnameinfo_atalk(sa, salen, host, hostlen,
  127. serv, servlen, flags);
  128. #endif /* !defined(__minix) */
  129. case AF_INET:
  130. case AF_INET6:
  131. return getnameinfo_inet(sa, salen, host, hostlen,
  132. serv, servlen, flags);
  133. #if !defined(__minix)
  134. case AF_LINK:
  135. return getnameinfo_link(sa, salen, host, hostlen,
  136. serv, servlen, flags);
  137. case AF_LOCAL:
  138. return getnameinfo_local(sa, salen, host, hostlen,
  139. serv, servlen, flags);
  140. #endif /* !defined(__minix) */
  141. default:
  142. return EAI_FAMILY;
  143. }
  144. }
  145. #if !defined(__minix)
  146. /*
  147. * getnameinfo_atalk():
  148. * Format an AppleTalk address into a printable format.
  149. */
  150. /* ARGSUSED */
  151. static int
  152. getnameinfo_atalk(const struct sockaddr *sa, socklen_t salen,
  153. char *host, socklen_t hostlen, char *serv, socklen_t servlen,
  154. int flags)
  155. {
  156. char numserv[8];
  157. int n, m=0;
  158. const struct sockaddr_at *sat =
  159. (const struct sockaddr_at *)(const void *)sa;
  160. if (serv != NULL && servlen > 0) {
  161. snprintf(numserv, sizeof(numserv), "%u", sat->sat_port);
  162. if (strlen(numserv) + 1 > servlen)
  163. return EAI_MEMORY;
  164. strlcpy(serv, numserv, servlen);
  165. }
  166. n = snprintf(host, hostlen, "%u.%u",
  167. ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
  168. if (n < 0 || (socklen_t)(m+n) >= hostlen)
  169. goto errout;
  170. m += n;
  171. if (sat->sat_range.r_netrange.nr_phase) {
  172. n = snprintf(host+m, hostlen-m, " phase %u",
  173. sat->sat_range.r_netrange.nr_phase);
  174. if (n < 0 || (socklen_t)(m+n) >= hostlen)
  175. goto errout;
  176. m += n;
  177. }
  178. if (sat->sat_range.r_netrange.nr_firstnet) {
  179. n = snprintf(host+m, hostlen-m, " range %u - %u",
  180. ntohs(sat->sat_range.r_netrange.nr_firstnet),
  181. ntohs(sat->sat_range.r_netrange.nr_lastnet ));
  182. if (n < 0 || (socklen_t)(m+n) >= hostlen)
  183. goto errout;
  184. m += n;
  185. }
  186. return 0;
  187. errout:
  188. if (host && hostlen>0)
  189. host[m] = '\0'; /* XXX ??? */
  190. return EAI_MEMORY;
  191. }
  192. /*
  193. * getnameinfo_local():
  194. * Format an local address into a printable format.
  195. */
  196. /* ARGSUSED */
  197. static int
  198. getnameinfo_local(const struct sockaddr *sa, socklen_t salen,
  199. char *host, socklen_t hostlen, char *serv, socklen_t servlen,
  200. int flags)
  201. {
  202. const struct sockaddr_un *sun =
  203. (const struct sockaddr_un *)(const void *)sa;
  204. if (serv != NULL && servlen > 0)
  205. serv[0] = '\0';
  206. if (host && hostlen > 0)
  207. strlcpy(host, sun->sun_path,
  208. MIN(sizeof(sun->sun_path) + 1, hostlen));
  209. return 0;
  210. }
  211. #endif /* !defined(__minix) */
  212. /*
  213. * getnameinfo_inet():
  214. * Format an IPv4 or IPv6 sockaddr into a printable string.
  215. */
  216. static int
  217. getnameinfo_inet(const struct sockaddr *sa, socklen_t salen,
  218. char *host, socklen_t hostlen,
  219. char *serv, socklen_t servlen,
  220. int flags)
  221. {
  222. const struct afd *afd;
  223. struct servent *sp;
  224. struct hostent *hp;
  225. u_short port;
  226. int family, i;
  227. const char *addr;
  228. uint32_t v4a;
  229. char numserv[512];
  230. char numaddr[512];
  231. /* sa is checked below */
  232. /* host may be NULL */
  233. /* serv may be NULL */
  234. if (sa == NULL)
  235. return EAI_FAIL;
  236. family = sa->sa_family;
  237. for (i = 0; afdl[i].a_af; i++)
  238. if (afdl[i].a_af == family) {
  239. afd = &afdl[i];
  240. goto found;
  241. }
  242. return EAI_FAMILY;
  243. found:
  244. if (salen != afd->a_socklen)
  245. return EAI_FAIL;
  246. /* network byte order */
  247. port = ((const struct sockinet *)(const void *)sa)->si_port;
  248. addr = (const char *)(const void *)sa + afd->a_off;
  249. if (serv == NULL || servlen == 0) {
  250. /*
  251. * do nothing in this case.
  252. * in case you are wondering if "&&" is more correct than
  253. * "||" here: rfc2553bis-03 says that serv == NULL OR
  254. * servlen == 0 means that the caller does not want the result.
  255. */
  256. } else {
  257. struct servent_data svd;
  258. struct servent sv;
  259. if (flags & NI_NUMERICSERV)
  260. sp = NULL;
  261. else {
  262. (void)memset(&svd, 0, sizeof(svd));
  263. sp = getservbyport_r(port,
  264. (flags & NI_DGRAM) ? "udp" : "tcp", &sv, &svd);
  265. }
  266. if (sp) {
  267. if (strlen(sp->s_name) + 1 > servlen) {
  268. endservent_r(&svd);
  269. return EAI_MEMORY;
  270. }
  271. strlcpy(serv, sp->s_name, servlen);
  272. endservent_r(&svd);
  273. } else {
  274. snprintf(numserv, sizeof(numserv), "%u", ntohs(port));
  275. if (strlen(numserv) + 1 > servlen)
  276. return EAI_MEMORY;
  277. strlcpy(serv, numserv, servlen);
  278. }
  279. }
  280. switch (sa->sa_family) {
  281. case AF_INET:
  282. v4a = (uint32_t)
  283. ntohl(((const struct sockaddr_in *)
  284. (const void *)sa)->sin_addr.s_addr);
  285. if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
  286. flags |= NI_NUMERICHOST;
  287. v4a >>= IN_CLASSA_NSHIFT;
  288. if (v4a == 0)
  289. flags |= NI_NUMERICHOST;
  290. break;
  291. #ifdef INET6
  292. case AF_INET6:
  293. {
  294. const struct sockaddr_in6 *sin6;
  295. sin6 = (const struct sockaddr_in6 *)(const void *)sa;
  296. switch (sin6->sin6_addr.s6_addr[0]) {
  297. case 0x00:
  298. if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
  299. ;
  300. else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
  301. ;
  302. else
  303. flags |= NI_NUMERICHOST;
  304. break;
  305. default:
  306. if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
  307. flags |= NI_NUMERICHOST;
  308. }
  309. else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
  310. flags |= NI_NUMERICHOST;
  311. break;
  312. }
  313. }
  314. break;
  315. #endif
  316. }
  317. if (host == NULL || hostlen == 0) {
  318. /*
  319. * do nothing in this case.
  320. * in case you are wondering if "&&" is more correct than
  321. * "||" here: rfc2553bis-03 says that host == NULL or
  322. * hostlen == 0 means that the caller does not want the result.
  323. */
  324. } else if (flags & NI_NUMERICHOST) {
  325. size_t numaddrlen;
  326. /* NUMERICHOST and NAMEREQD conflicts with each other */
  327. if (flags & NI_NAMEREQD)
  328. return EAI_NONAME;
  329. switch(afd->a_af) {
  330. #ifdef INET6
  331. case AF_INET6:
  332. {
  333. int error;
  334. if ((error = ip6_parsenumeric(sa, addr, host,
  335. hostlen, flags)) != 0)
  336. return(error);
  337. break;
  338. }
  339. #endif
  340. default:
  341. if (inet_ntop(afd->a_af, addr, numaddr,
  342. (socklen_t)sizeof(numaddr)) == NULL)
  343. return EAI_SYSTEM;
  344. numaddrlen = strlen(numaddr);
  345. if (numaddrlen + 1 > hostlen) /* don't forget terminator */
  346. return EAI_MEMORY;
  347. strlcpy(host, numaddr, hostlen);
  348. break;
  349. }
  350. } else {
  351. struct hostent hent;
  352. char hbuf[4096];
  353. int he;
  354. hp = gethostbyaddr_r(addr, afd->a_addrlen, afd->a_af, &hent,
  355. hbuf, sizeof(hbuf), &he);
  356. if (hp) {
  357. #if 0
  358. /*
  359. * commented out, since "for local host" is not
  360. * implemented here - see RFC2553 p30
  361. */
  362. if (flags & NI_NOFQDN) {
  363. char *p;
  364. p = strchr(hp->h_name, '.');
  365. if (p)
  366. *p = '\0';
  367. }
  368. #endif
  369. if (strlen(hp->h_name) + 1 > hostlen) {
  370. return EAI_MEMORY;
  371. }
  372. strlcpy(host, hp->h_name, hostlen);
  373. } else {
  374. switch (he) {
  375. case NO_DATA:
  376. case HOST_NOT_FOUND:
  377. if (flags & NI_NAMEREQD)
  378. return EAI_NONAME;
  379. break;
  380. case TRY_AGAIN:
  381. return EAI_AGAIN;
  382. case NETDB_SUCCESS:
  383. case NETDB_INTERNAL:
  384. case NO_RECOVERY:
  385. /*FALLTHROUGH*/
  386. default:
  387. return EAI_SYSTEM;
  388. }
  389. switch(afd->a_af) {
  390. #ifdef INET6
  391. case AF_INET6:
  392. {
  393. int error;
  394. if ((error = ip6_parsenumeric(sa, addr, host,
  395. hostlen,
  396. flags)) != 0)
  397. return(error);
  398. break;
  399. }
  400. #endif
  401. default:
  402. if (inet_ntop(afd->a_af, addr, host,
  403. hostlen) == NULL)
  404. return EAI_SYSTEM;
  405. break;
  406. }
  407. }
  408. }
  409. return(0);
  410. }
  411. #ifdef INET6
  412. static int
  413. ip6_parsenumeric(const struct sockaddr *sa, const char *addr, char *host,
  414. socklen_t hostlen, int flags)
  415. {
  416. size_t numaddrlen;
  417. char numaddr[512];
  418. _DIAGASSERT(sa != NULL);
  419. _DIAGASSERT(addr != NULL);
  420. _DIAGASSERT(host != NULL);
  421. if (inet_ntop(AF_INET6, addr, numaddr, (socklen_t)sizeof(numaddr))
  422. == NULL)
  423. return EAI_SYSTEM;
  424. numaddrlen = strlen(numaddr);
  425. if (numaddrlen + 1 > hostlen) /* don't forget terminator */
  426. return EAI_OVERFLOW;
  427. strlcpy(host, numaddr, hostlen);
  428. if (((const struct sockaddr_in6 *)(const void *)sa)->sin6_scope_id) {
  429. char zonebuf[MAXHOSTNAMELEN];
  430. int zonelen;
  431. zonelen = ip6_sa2str(
  432. (const struct sockaddr_in6 *)(const void *)sa,
  433. zonebuf, sizeof(zonebuf), flags);
  434. if (zonelen < 0)
  435. return EAI_OVERFLOW;
  436. if ((size_t) zonelen + 1 + numaddrlen + 1 > hostlen)
  437. return EAI_OVERFLOW;
  438. /* construct <numeric-addr><delim><zoneid> */
  439. memcpy(host + numaddrlen + 1, zonebuf,
  440. (size_t)zonelen);
  441. host[numaddrlen] = SCOPE_DELIMITER;
  442. host[numaddrlen + 1 + zonelen] = '\0';
  443. }
  444. return 0;
  445. }
  446. /* ARGSUSED */
  447. static int
  448. ip6_sa2str(const struct sockaddr_in6 *sa6, char *buf, size_t bufsiz, int flags)
  449. {
  450. unsigned int ifindex;
  451. const struct in6_addr *a6;
  452. int n;
  453. _DIAGASSERT(sa6 != NULL);
  454. _DIAGASSERT(buf != NULL);
  455. ifindex = (unsigned int)sa6->sin6_scope_id;
  456. a6 = &sa6->sin6_addr;
  457. #ifdef NI_NUMERICSCOPE
  458. if ((flags & NI_NUMERICSCOPE) != 0) {
  459. n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
  460. if (n < 0 || (size_t)n >= bufsiz)
  461. return -1;
  462. else
  463. return n;
  464. }
  465. #endif
  466. /* if_indextoname() does not take buffer size. not a good api... */
  467. if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) &&
  468. bufsiz >= IF_NAMESIZE) {
  469. char *p = if_indextoname(ifindex, buf);
  470. if (p) {
  471. return (int)strlen(p);
  472. }
  473. }
  474. /* last resort */
  475. n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
  476. if (n < 0 || (size_t) n >= bufsiz)
  477. return -1;
  478. else
  479. return n;
  480. }
  481. #endif /* INET6 */
  482. #if !defined(__minix)
  483. /*
  484. * getnameinfo_link():
  485. * Format a link-layer address into a printable format, paying attention to
  486. * the interface type.
  487. */
  488. /* ARGSUSED */
  489. static int
  490. getnameinfo_link(const struct sockaddr *sa, socklen_t salen,
  491. char *host, socklen_t hostlen, char *serv, socklen_t servlen,
  492. int flags)
  493. {
  494. const struct sockaddr_dl *sdl =
  495. (const struct sockaddr_dl *)(const void *)sa;
  496. const struct ieee1394_hwaddr *iha;
  497. int n;
  498. if (serv != NULL && servlen > 0)
  499. *serv = '\0';
  500. if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && sdl->sdl_slen == 0) {
  501. n = snprintf(host, hostlen, "link#%u", sdl->sdl_index);
  502. goto out;
  503. }
  504. switch (sdl->sdl_type) {
  505. #ifdef IFT_ECONET
  506. case IFT_ECONET:
  507. if (sdl->sdl_alen < 2)
  508. return EAI_FAMILY;
  509. if (CLLADDR(sdl)[1] == 0)
  510. n = snprintf(host, hostlen, "%u", CLLADDR(sdl)[0]);
  511. else
  512. n = snprintf(host, hostlen, "%u.%u",
  513. CLLADDR(sdl)[1], CLLADDR(sdl)[0]);
  514. goto out;
  515. #endif
  516. case IFT_IEEE1394:
  517. if (sdl->sdl_alen < sizeof(iha->iha_uid))
  518. return EAI_FAMILY;
  519. iha =
  520. (const struct ieee1394_hwaddr *)(const void *)CLLADDR(sdl);
  521. return hexname(iha->iha_uid, sizeof(iha->iha_uid),
  522. host, hostlen);
  523. /*
  524. * The following have zero-length addresses.
  525. * IFT_ATM (net/if_atmsubr.c)
  526. * IFT_FAITH (net/if_faith.c)
  527. * IFT_GIF (net/if_gif.c)
  528. * IFT_LOOP (net/if_loop.c)
  529. * IFT_PPP (net/if_ppp.c, net/if_spppsubr.c)
  530. * IFT_SLIP (net/if_sl.c, net/if_strip.c)
  531. * IFT_STF (net/if_stf.c)
  532. * IFT_L2VLAN (net/if_vlan.c)
  533. * IFT_PROPVIRTUAL (net/if_bridge.h>
  534. */
  535. /*
  536. * The following use IPv4 addresses as link-layer addresses:
  537. * IFT_OTHER (net/if_gre.c)
  538. */
  539. case IFT_ARCNET: /* default below is believed correct for all these. */
  540. case IFT_ETHER:
  541. case IFT_FDDI:
  542. case IFT_HIPPI:
  543. case IFT_ISO88025:
  544. default:
  545. return hexname((const uint8_t *)CLLADDR(sdl),
  546. (size_t)sdl->sdl_alen, host, hostlen);
  547. }
  548. out:
  549. if (n < 0 || (socklen_t) n >= hostlen) {
  550. *host = '\0';
  551. return EAI_MEMORY;
  552. }
  553. return 0;
  554. }
  555. static int
  556. hexname(const uint8_t *cp, size_t len, char *host, socklen_t hostlen)
  557. {
  558. int n;
  559. size_t i;
  560. char *outp = host;
  561. *outp = '\0';
  562. for (i = 0; i < len; i++) {
  563. n = snprintf(outp, hostlen, "%s%02x",
  564. i ? ":" : "", cp[i]);
  565. if (n < 0 || (socklen_t) n >= hostlen) {
  566. *host = '\0';
  567. return EAI_MEMORY;
  568. }
  569. outp += n;
  570. hostlen -= n;
  571. }
  572. return 0;
  573. }
  574. #endif /* !defined(__minix) */