getaddrinfo.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. #include <stdlib.h>
  2. #include <sys/socket.h>
  3. #include <netinet/in.h>
  4. #include <netdb.h>
  5. #include <string.h>
  6. #include <pthread.h>
  7. #include <unistd.h>
  8. #include <endian.h>
  9. #include <errno.h>
  10. #include "lookup.h"
  11. int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res)
  12. {
  13. struct service ports[MAXSERVS];
  14. struct address addrs[MAXADDRS];
  15. char canon[256], *outcanon;
  16. int nservs, naddrs, nais, canon_len, i, j, k;
  17. int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0;
  18. int no_family = 0;
  19. struct aibuf *out;
  20. if (!host && !serv) return EAI_NONAME;
  21. if (hint) {
  22. family = hint->ai_family;
  23. flags = hint->ai_flags;
  24. proto = hint->ai_protocol;
  25. socktype = hint->ai_socktype;
  26. const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST |
  27. AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG | AI_NUMERICSERV;
  28. if ((flags & mask) != flags)
  29. return EAI_BADFLAGS;
  30. switch (family) {
  31. case AF_INET:
  32. case AF_INET6:
  33. case AF_UNSPEC:
  34. break;
  35. default:
  36. return EAI_FAMILY;
  37. }
  38. }
  39. if (flags & AI_ADDRCONFIG) {
  40. /* Define the "an address is configured" condition for address
  41. * families via ability to create a socket for the family plus
  42. * routability of the loopback address for the family. */
  43. static const struct sockaddr_in lo4 = {
  44. .sin_family = AF_INET, .sin_port = 65535,
  45. .sin_addr.s_addr = __BYTE_ORDER == __BIG_ENDIAN
  46. ? 0x7f000001 : 0x0100007f
  47. };
  48. static const struct sockaddr_in6 lo6 = {
  49. .sin6_family = AF_INET6, .sin6_port = 65535,
  50. .sin6_addr = IN6ADDR_LOOPBACK_INIT
  51. };
  52. int tf[2] = { AF_INET, AF_INET6 };
  53. const void *ta[2] = { &lo4, &lo6 };
  54. socklen_t tl[2] = { sizeof lo4, sizeof lo6 };
  55. for (i=0; i<2; i++) {
  56. if (family==tf[1-i]) continue;
  57. int s = socket(tf[i], SOCK_CLOEXEC|SOCK_DGRAM,
  58. IPPROTO_UDP);
  59. if (s>=0) {
  60. int cs;
  61. pthread_setcancelstate(
  62. PTHREAD_CANCEL_DISABLE, &cs);
  63. int r = connect(s, ta[i], tl[i]);
  64. int saved_errno = errno;
  65. pthread_setcancelstate(cs, 0);
  66. close(s);
  67. if (!r) continue;
  68. errno = saved_errno;
  69. }
  70. switch (errno) {
  71. case EADDRNOTAVAIL:
  72. case EAFNOSUPPORT:
  73. case EHOSTUNREACH:
  74. case ENETDOWN:
  75. case ENETUNREACH:
  76. break;
  77. default:
  78. return EAI_SYSTEM;
  79. }
  80. if (family == tf[i]) no_family = 1;
  81. family = tf[1-i];
  82. }
  83. }
  84. nservs = __lookup_serv(ports, serv, proto, socktype, flags);
  85. if (nservs < 0) return nservs;
  86. naddrs = __lookup_name(addrs, canon, host, family, flags);
  87. if (naddrs < 0) return naddrs;
  88. if (no_family) return EAI_NODATA;
  89. nais = nservs * naddrs;
  90. canon_len = strlen(canon);
  91. out = calloc(1, nais * sizeof(*out) + canon_len + 1);
  92. if (!out) return EAI_MEMORY;
  93. if (canon_len) {
  94. outcanon = (void *)&out[nais];
  95. memcpy(outcanon, canon, canon_len+1);
  96. } else {
  97. outcanon = 0;
  98. }
  99. for (k=i=0; i<naddrs; i++) for (j=0; j<nservs; j++, k++) {
  100. out[k].slot = k;
  101. out[k].ai = (struct addrinfo){
  102. .ai_family = addrs[i].family,
  103. .ai_socktype = ports[j].socktype,
  104. .ai_protocol = ports[j].proto,
  105. .ai_addrlen = addrs[i].family == AF_INET
  106. ? sizeof(struct sockaddr_in)
  107. : sizeof(struct sockaddr_in6),
  108. .ai_addr = (void *)&out[k].sa,
  109. .ai_canonname = outcanon };
  110. if (k) out[k-1].ai.ai_next = &out[k].ai;
  111. switch (addrs[i].family) {
  112. case AF_INET:
  113. out[k].sa.sin.sin_family = AF_INET;
  114. out[k].sa.sin.sin_port = htons(ports[j].port);
  115. memcpy(&out[k].sa.sin.sin_addr, &addrs[i].addr, 4);
  116. break;
  117. case AF_INET6:
  118. out[k].sa.sin6.sin6_family = AF_INET6;
  119. out[k].sa.sin6.sin6_port = htons(ports[j].port);
  120. out[k].sa.sin6.sin6_scope_id = addrs[i].scopeid;
  121. memcpy(&out[k].sa.sin6.sin6_addr, &addrs[i].addr, 16);
  122. break;
  123. }
  124. }
  125. out[0].ref = nais;
  126. *res = &out->ai;
  127. return 0;
  128. }