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

/support/support_format_addrinfo.c

https://gitlab.com/gbenson/glibc
C | 242 lines | 199 code | 18 blank | 25 comment | 37 complexity | 4b339c52d37af179a2d5560dbba105a4 MD5 | raw file
  1. /* Convert struct addrinfo values to a string.
  2. Copyright (C) 2016-2018 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #include <support/format_nss.h>
  16. #include <arpa/inet.h>
  17. #include <errno.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <support/support.h>
  21. #include <support/xmemstream.h>
  22. static size_t
  23. socket_address_length (int family)
  24. {
  25. switch (family)
  26. {
  27. case AF_INET:
  28. return sizeof (struct sockaddr_in);
  29. case AF_INET6:
  30. return sizeof (struct sockaddr_in6);
  31. default:
  32. return -1;
  33. }
  34. }
  35. static void
  36. format_ai_flags_1 (FILE *out, struct addrinfo *ai, int flag, const char *name,
  37. int * flags_printed)
  38. {
  39. if ((ai->ai_flags & flag) != 0)
  40. fprintf (out, " %s", name);
  41. *flags_printed |= flag;
  42. }
  43. static void
  44. format_ai_flags (FILE *out, struct addrinfo *ai)
  45. {
  46. if (ai == NULL)
  47. return;
  48. if (ai->ai_flags != 0)
  49. {
  50. fprintf (out, "flags:");
  51. int flags_printed = 0;
  52. #define FLAG(flag) format_ai_flags_1 (out, ai, flag, #flag, &flags_printed)
  53. FLAG (AI_PASSIVE);
  54. FLAG (AI_CANONNAME);
  55. FLAG (AI_NUMERICHOST);
  56. FLAG (AI_V4MAPPED);
  57. FLAG (AI_ALL);
  58. FLAG (AI_ADDRCONFIG);
  59. FLAG (AI_IDN);
  60. FLAG (AI_CANONIDN);
  61. FLAG (AI_NUMERICSERV);
  62. #undef FLAG
  63. int remaining = ai->ai_flags & ~flags_printed;
  64. if (remaining != 0)
  65. fprintf (out, " %08x", remaining);
  66. fprintf (out, "\n");
  67. }
  68. /* Report flag mismatches within the list. */
  69. int flags = ai->ai_flags;
  70. int index = 1;
  71. ai = ai->ai_next;
  72. while (ai != NULL)
  73. {
  74. if (ai->ai_flags != flags)
  75. fprintf (out, "error: flags at %d: 0x%x expected, 0x%x actual\n",
  76. index, flags, ai->ai_flags);
  77. ai = ai->ai_next;
  78. ++index;
  79. }
  80. }
  81. static void
  82. format_ai_canonname (FILE *out, struct addrinfo *ai)
  83. {
  84. if (ai == NULL)
  85. return;
  86. if (ai->ai_canonname != NULL)
  87. fprintf (out, "canonname: %s\n", ai->ai_canonname);
  88. /* Report incorrectly set ai_canonname fields on subsequent list
  89. entries. */
  90. int index = 1;
  91. ai = ai->ai_next;
  92. while (ai != NULL)
  93. {
  94. if (ai->ai_canonname != NULL)
  95. fprintf (out, "error: canonname set at %d: %s\n",
  96. index, ai->ai_canonname);
  97. ai = ai->ai_next;
  98. ++index;
  99. }
  100. }
  101. static void
  102. format_ai_one (FILE *out, struct addrinfo *ai)
  103. {
  104. {
  105. char type_buf[32];
  106. const char *type_str;
  107. char proto_buf[32];
  108. const char *proto_str;
  109. /* ai_socktype */
  110. switch (ai->ai_socktype)
  111. {
  112. case SOCK_RAW:
  113. type_str = "RAW";
  114. break;
  115. case SOCK_DGRAM:
  116. type_str = "DGRAM";
  117. break;
  118. case SOCK_STREAM:
  119. type_str = "STREAM";
  120. break;
  121. default:
  122. snprintf (type_buf, sizeof (type_buf), "%d", ai->ai_socktype);
  123. type_str = type_buf;
  124. }
  125. /* ai_protocol */
  126. switch (ai->ai_protocol)
  127. {
  128. case IPPROTO_IP:
  129. proto_str = "IP";
  130. break;
  131. case IPPROTO_UDP:
  132. proto_str = "UDP";
  133. break;
  134. case IPPROTO_TCP:
  135. proto_str = "TCP";
  136. break;
  137. default:
  138. snprintf (proto_buf, sizeof (proto_buf), "%d", ai->ai_protocol);
  139. proto_str = proto_buf;
  140. }
  141. fprintf (out, "address: %s/%s", type_str, proto_str);
  142. }
  143. /* ai_addrlen */
  144. if (ai->ai_addrlen != socket_address_length (ai->ai_family))
  145. {
  146. char *family = support_format_address_family (ai->ai_family);
  147. fprintf (out, "error: invalid address length %d for %s\n",
  148. ai->ai_addrlen, family);
  149. free (family);
  150. }
  151. /* ai_addr */
  152. {
  153. char buf[128];
  154. uint16_t port;
  155. const char *ret;
  156. switch (ai->ai_family)
  157. {
  158. case AF_INET:
  159. {
  160. struct sockaddr_in *sin = (struct sockaddr_in *) ai->ai_addr;
  161. ret = inet_ntop (AF_INET, &sin->sin_addr, buf, sizeof (buf));
  162. port = sin->sin_port;
  163. }
  164. break;
  165. case AF_INET6:
  166. {
  167. struct sockaddr_in6 *sin = (struct sockaddr_in6 *) ai->ai_addr;
  168. ret = inet_ntop (AF_INET6, &sin->sin6_addr, buf, sizeof (buf));
  169. port = sin->sin6_port;
  170. }
  171. break;
  172. default:
  173. errno = EAFNOSUPPORT;
  174. ret = NULL;
  175. }
  176. if (ret == NULL)
  177. fprintf (out, "error: inet_top failed: %m\n");
  178. else
  179. fprintf (out, " %s %u\n", buf, ntohs (port));
  180. }
  181. }
  182. /* Format all the addresses in one address family. */
  183. static void
  184. format_ai_family (FILE *out, struct addrinfo *ai, int family)
  185. {
  186. while (ai)
  187. {
  188. if (ai->ai_family == family)
  189. format_ai_one (out, ai);
  190. ai = ai->ai_next;
  191. }
  192. }
  193. char *
  194. support_format_addrinfo (struct addrinfo *ai, int ret)
  195. {
  196. int errno_copy = errno;
  197. struct xmemstream mem;
  198. xopen_memstream (&mem);
  199. if (ret != 0)
  200. {
  201. const char *errmsg = gai_strerror (ret);
  202. if (strcmp (errmsg, "Unknown error") == 0)
  203. fprintf (mem.out, "error: Unknown error %d\n", ret);
  204. else
  205. fprintf (mem.out, "error: %s\n", errmsg);
  206. if (ret == EAI_SYSTEM)
  207. {
  208. errno = errno_copy;
  209. fprintf (mem.out, "error: %m\n");
  210. }
  211. }
  212. else
  213. {
  214. format_ai_flags (mem.out, ai);
  215. format_ai_canonname (mem.out, ai);
  216. format_ai_family (mem.out, ai, AF_INET);
  217. format_ai_family (mem.out, ai, AF_INET6);
  218. }
  219. xfclose_memstream (&mem);
  220. return mem.buffer;
  221. }