getaddrinfo.c 3.6 KB

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