PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/tcpreen-1.4.4/libsolve/solve.c

#
C | 322 lines | 225 code | 43 blank | 54 comment | 54 complexity | 976c424227c4dbfb90e2b4a6fc21578d MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * solve.c - Secure RFC-2553-based IP resolution functions
  3. * $Id: solve.c 175 2005-07-01 18:07:39Z rdenisc $
  4. */
  5. /***********************************************************************
  6. * Copyright (C) 2002-2004 Remi Denis-Courmont. *
  7. * This program is free software; you can redistribute and/or modify *
  8. * it under the terms of the GNU General Public License as published *
  9. * by the Free Software Foundation; version 2 of the license. *
  10. * *
  11. * This program is distributed in the hope that it will be useful, *
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
  14. * See the GNU General Public License for more details. *
  15. * *
  16. * You should have received a copy of the GNU General Public License *
  17. * along with this program; if not, you can get it from: *
  18. * http://www.gnu.org/copyleft/gpl.html *
  19. ***********************************************************************/
  20. #ifdef HAVE_CONFIG_H
  21. # include <config.h>
  22. #endif
  23. #include <stdio.h> /* stderr */
  24. #include "secstr.h" /* memset(), memcpy(), strcmp() */
  25. #include <stdlib.h> /* malloc(), free() */
  26. #include <sys/types.h> /* needed before sys/socket.h on FreeBSD */
  27. #if HAVE_SYS_SOCKET_H
  28. # include <sys/socket.h> /* getsockname(), getpeername() */
  29. #endif
  30. #if HAVE_SYS_UN_H
  31. # include <sys/un.h>
  32. #endif
  33. #include <errno.h>
  34. #include "solve.h"
  35. /*
  36. * Compares 2 socket addresses. Return 0 if they are identical,
  37. * a positive if they are different, a negative on error. It is assumed
  38. * that they are of the same size (otherwise, YOU know they are
  39. * different anyway, don't you?).
  40. *
  41. * Only nodes are compared, services are not.
  42. */
  43. static int
  44. sockaddrcmp (const struct sockaddr *a1, size_t a1len,
  45. const struct sockaddr *a2, size_t a2len)
  46. {
  47. char n1[NI_MAXHOST], n2[NI_MAXHOST];
  48. /* Normally, we'd compare addr and res->ai_addr, but there is
  49. no address family independant way to do this (memcmp() won't
  50. work in many case (at least Linux/IPv4).
  51. Instead, we do compare numerical address strings. This requires
  52. yet another (but fortunately non-blocking) call of getnameinfo.
  53. It is moreover assumed that service names cannot be spoofed
  54. (Service Name Service has not been invented, right?).
  55. */
  56. if ((a1->sa_family != a2->sa_family)
  57. || getnameinfo (a1, a1len, n1, sizeof (n1), NULL, 0, NI_NUMERICHOST)
  58. || getnameinfo (a2, a2len, n2, sizeof (n2), NULL, 0, NI_NUMERICHOST))
  59. return -1;
  60. return (strcmp (n1, n2) == 0) ? 0 : 1;
  61. }
  62. /*
  63. * Secure reverse DNS resolution.
  64. * NI_NOFQDN (flags option) will fail unless addr is on the same domain
  65. * as we are (this is absolutely normal). All other flags should work
  66. * correctly.
  67. *
  68. * In case of error, if *servbuf is true, the service name is ok.
  69. */
  70. static int
  71. secure_getnameinfo(const struct sockaddr *addr, size_t addrlen,
  72. char *namebuf, size_t namelen,
  73. char *servbuf, size_t servlen, int flags)
  74. {
  75. int check;
  76. /* Gets service name once and for all */
  77. check = getnameinfo (addr, addrlen, NULL, 0, servbuf, servlen,
  78. flags);
  79. if (check != 0)
  80. return check;
  81. /* Reverse DNS request */
  82. check = getnameinfo (addr, addrlen, namebuf, namelen, NULL, 0, flags);
  83. if ((check != 0) || (flags & NI_NUMERICHOST))
  84. return check; /* If numeric host name is requested, done. */
  85. else
  86. {
  87. struct addrinfo hints, *res, *info;
  88. /* Hostname DNS request (to prevent malicious users
  89. * from DNS spoofing us). */
  90. memset (&hints, 0, sizeof (hints));
  91. hints.ai_family = addr->sa_family;
  92. check = getaddrinfo (namebuf, NULL, &hints, &res);
  93. if (check == 0)
  94. {
  95. for (info = res; info != NULL; info = info->ai_next)
  96. if (!sockaddrcmp (addr, addrlen, info->ai_addr,
  97. info->ai_addrlen))
  98. {
  99. freeaddrinfo(res);
  100. return 0;
  101. }
  102. /* DNS spoofing detected: use numeric address only */
  103. freeaddrinfo (res);
  104. }
  105. }
  106. return getnameinfo (addr, addrlen, namebuf, namelen, NULL, 0,
  107. flags|NI_NUMERICHOST);
  108. }
  109. /*** Generic struct addrinfo handling ***/
  110. void
  111. freeai (struct addrinfo *res)
  112. {
  113. if (res != NULL)
  114. {
  115. freeai (res->ai_next);
  116. if (res->ai_addr != NULL)
  117. free (res->ai_addr);
  118. free (res);
  119. }
  120. }
  121. struct addrinfo *
  122. makeai (const struct sockaddr *addr, socklen_t addrlen)
  123. {
  124. struct addrinfo *res = (struct addrinfo *)
  125. malloc (sizeof (struct addrinfo));
  126. if (res == NULL)
  127. return NULL;
  128. memset (res, 0, sizeof (struct addrinfo));
  129. if (addr != NULL)
  130. {
  131. struct sockaddr *ad = (struct sockaddr *)
  132. malloc (addrlen);
  133. if (ad == NULL)
  134. {
  135. int errb = errno;
  136. free (res);
  137. errno = errb;
  138. return NULL;
  139. }
  140. memcpy (ad, addr, addrlen);
  141. res->ai_addr = ad;
  142. }
  143. res->ai_addrlen = addrlen;
  144. return res;
  145. }
  146. struct addrinfo *
  147. copyai (const struct addrinfo *src)
  148. {
  149. if (src != NULL)
  150. {
  151. struct addrinfo *res;
  152. res = (struct addrinfo *)malloc (sizeof (struct addrinfo));
  153. if (res == NULL)
  154. return NULL;
  155. memcpy (res, src, sizeof (struct addrinfo));
  156. if (src->ai_next != NULL)
  157. {
  158. res->ai_next = copyai (src->ai_next);
  159. if (res->ai_next == NULL)
  160. {
  161. int errb = errno;
  162. free (res);
  163. errno = errb;
  164. return NULL;
  165. }
  166. }
  167. if (src->ai_addr != NULL)
  168. {
  169. res->ai_addr =
  170. (struct sockaddr *)malloc (src->ai_addrlen);
  171. if (res->ai_addr == NULL)
  172. {
  173. int errb = errno;
  174. freeai (res->ai_next);
  175. free (res);
  176. errno = errb;
  177. return NULL;
  178. }
  179. memcpy (res->ai_addr, src->ai_addr, src->ai_addrlen);
  180. }
  181. return res;
  182. }
  183. return NULL;
  184. }
  185. #if HAVE_SYS_UN_H
  186. /*** Unix (a.k.a. "local") addresses ***/
  187. static int
  188. unix_getaddrinfo (const char *path, const struct addrinfo *hints,
  189. struct addrinfo **res)
  190. {
  191. if (path != NULL)
  192. {
  193. struct sockaddr_un addr;
  194. struct addrinfo *ret;
  195. memset (&addr, 0, sizeof (addr));
  196. addr.sun_family = AF_LOCAL;
  197. # ifdef HAVE_SA_LEN
  198. addr.sun_len = sizeof (addr);
  199. # endif
  200. strncpy (addr.sun_path, path, sizeof (addr.sun_path));
  201. if (addr.sun_path[sizeof (addr.sun_path) - 1])
  202. return EAI_NONAME;
  203. ret = makeai ((struct sockaddr *)&addr, sizeof (addr));
  204. if (ret == NULL)
  205. return EAI_MEMORY;
  206. ret->ai_family = AF_LOCAL;
  207. ret->ai_socktype = hints->ai_socktype ?: SOCK_DGRAM;
  208. *res = ret;
  209. return 0;
  210. }
  211. return EAI_NONAME;
  212. }
  213. #endif
  214. /*** Protocols family-independant addresses resolution ***/
  215. int getnamebyaddr (const struct sockaddr *addr, size_t addrlen,
  216. char *nodename, size_t nlen, char *service,
  217. size_t slen, int flags)
  218. {
  219. switch (addr->sa_family)
  220. {
  221. case AF_INET:
  222. #ifdef AF_INET6
  223. case AF_INET6:
  224. #endif
  225. return secure_getnameinfo (addr, addrlen, nodename,
  226. nlen, service, slen, flags);
  227. #if HAVE_SYS_UN_H
  228. case AF_LOCAL:
  229. *nodename = 0;
  230. secure_strncpy (service,
  231. ((struct sockaddr_un *)addr)->sun_path,
  232. slen);
  233. return 0;
  234. #endif
  235. }
  236. return EAI_FAMILY;
  237. }
  238. int
  239. getaddrbyname (const char *node, const char *service,
  240. const struct addrinfo *hints, struct addrinfo **res)
  241. {
  242. switch ((hints != NULL) ? hints->ai_family : 0)
  243. {
  244. case 0:
  245. case AF_INET:
  246. #ifdef AF_INET6
  247. case AF_INET6:
  248. #endif
  249. {
  250. int check;
  251. struct addrinfo *inet_res, inet_hints;
  252. if (hints != NULL)
  253. memcpy (&inet_hints, hints,
  254. sizeof (struct addrinfo));
  255. else
  256. memset (&inet_hints, 0,
  257. sizeof (struct addrinfo));
  258. inet_hints.ai_flags |= AI_IDN;
  259. // Avoids unknown service error
  260. if ((node == NULL) && (service == NULL))
  261. service = "0";
  262. check = getaddrinfo (node, service, &inet_hints,
  263. &inet_res);
  264. if (check)
  265. return check;
  266. *res = copyai (inet_res);
  267. freeaddrinfo (inet_res);
  268. return (*res == NULL) ? EAI_SYSTEM : 0;
  269. }
  270. #if HAVE_SYS_UN_H
  271. case AF_LOCAL:
  272. return (node != NULL) ? EAI_SERVICE
  273. : unix_getaddrinfo (service, hints, res);
  274. #endif
  275. }
  276. return EAI_FAMILY;
  277. }