resolve.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2003 by Alexander Barton (alex@barton.de)
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. * Please read the file COPYING, README and AUTHORS for more information.
  10. *
  11. * Asynchronous resolver
  12. */
  13. #include "portab.h"
  14. static char UNUSED id[] = "$Id: resolve.c,v 1.24.2.2 2006/12/17 22:59:56 fw Exp $";
  15. #include "imp.h"
  16. #include <assert.h>
  17. #include <errno.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <unistd.h>
  21. #include <sys/socket.h>
  22. #include <netinet/in.h>
  23. #include <arpa/inet.h>
  24. #include <netdb.h>
  25. #ifdef IDENTAUTH
  26. #ifdef HAVE_IDENT_H
  27. #include <ident.h>
  28. #endif
  29. #endif
  30. #include "conn.h"
  31. #include "defines.h"
  32. #include "log.h"
  33. #include "exp.h"
  34. #include "resolve.h"
  35. #include "io.h"
  36. static void Do_ResolveAddr PARAMS(( struct sockaddr_in *Addr, int Sock, int w_fd ));
  37. static void Do_ResolveName PARAMS(( const char *Host, int w_fd ));
  38. static bool register_callback PARAMS((RES_STAT *s, void (*cbfunc)(int, short)));
  39. #ifdef h_errno
  40. static char *Get_Error PARAMS(( int H_Error ));
  41. #endif
  42. static pid_t
  43. Resolver_fork(int *pipefds)
  44. {
  45. pid_t pid;
  46. if (pipe(pipefds) != 0) {
  47. Log( LOG_ALERT, "Resolver: Can't create output pipe: %s!", strerror( errno ));
  48. return -1;
  49. }
  50. pid = fork();
  51. switch(pid) {
  52. case -1:
  53. Log( LOG_CRIT, "Resolver: Can't fork: %s!", strerror( errno ));
  54. close(pipefds[0]);
  55. close(pipefds[1]);
  56. return -1;
  57. case 0: /* child */
  58. close(pipefds[0]);
  59. Log_Init_Resolver( );
  60. return 0;
  61. }
  62. /* parent */
  63. close(pipefds[1]);
  64. return pid;
  65. }
  66. /**
  67. * Resolve IP (asynchronous!).
  68. */
  69. GLOBAL bool
  70. Resolve_Addr(RES_STAT * s, struct sockaddr_in *Addr, int identsock,
  71. void (*cbfunc) (int, short))
  72. {
  73. int pipefd[2];
  74. pid_t pid;
  75. assert(s != NULL);
  76. pid = Resolver_fork(pipefd);
  77. if (pid > 0) {
  78. #ifdef DEBUG
  79. Log( LOG_DEBUG, "Resolver for %s created (PID %d).", inet_ntoa( Addr->sin_addr ), pid );
  80. #endif
  81. s->pid = pid;
  82. s->resolver_fd = pipefd[0];
  83. return register_callback(s, cbfunc);
  84. } else if( pid == 0 ) {
  85. /* Sub process */
  86. Do_ResolveAddr( Addr, identsock, pipefd[1]);
  87. Log_Exit_Resolver( );
  88. exit(0);
  89. }
  90. return false;
  91. } /* Resolve_Addr */
  92. /**
  93. * Resolve hostname (asynchronous!).
  94. */
  95. GLOBAL bool
  96. Resolve_Name( RES_STAT *s, const char *Host, void (*cbfunc)(int, short))
  97. {
  98. int pipefd[2];
  99. pid_t pid;
  100. assert(s != NULL);
  101. pid = Resolver_fork(pipefd);
  102. if (pid > 0) {
  103. /* Main process */
  104. #ifdef DEBUG
  105. Log( LOG_DEBUG, "Resolver for \"%s\" created (PID %d).", Host, pid );
  106. #endif
  107. s->pid = pid;
  108. s->resolver_fd = pipefd[0];
  109. return register_callback(s, cbfunc);
  110. } else if( pid == 0 ) {
  111. /* Sub process */
  112. Do_ResolveName(Host, pipefd[1]);
  113. Log_Exit_Resolver( );
  114. exit(0);
  115. }
  116. return false;
  117. } /* Resolve_Name */
  118. GLOBAL void
  119. Resolve_Init(RES_STAT *s)
  120. {
  121. assert(s != NULL);
  122. s->resolver_fd = -1;
  123. s->pid = 0;
  124. }
  125. static void
  126. Do_ResolveAddr( struct sockaddr_in *Addr, int identsock, int w_fd )
  127. {
  128. /* Resolver sub-process: resolve IP address and write result into
  129. * pipe to parent. */
  130. char hostname[HOST_LEN];
  131. char ipstr[HOST_LEN];
  132. struct hostent *h;
  133. size_t len;
  134. struct in_addr *addr;
  135. char *ntoaptr;
  136. array resolved_addr;
  137. #ifdef IDENTAUTH
  138. char *res;
  139. #endif
  140. array_init(&resolved_addr);
  141. /* Resolve IP address */
  142. #ifdef DEBUG
  143. Log_Resolver( LOG_DEBUG, "Now resolving %s ...", inet_ntoa( Addr->sin_addr ));
  144. #endif
  145. h = gethostbyaddr( (char *)&Addr->sin_addr, sizeof( Addr->sin_addr ), AF_INET );
  146. if (!h) {
  147. #ifdef h_errno
  148. Log_Resolver( LOG_WARNING, "Can't resolve address \"%s\": %s!", inet_ntoa( Addr->sin_addr ), Get_Error( h_errno ));
  149. #else
  150. Log_Resolver( LOG_WARNING, "Can't resolve address \"%s\"!", inet_ntoa( Addr->sin_addr ));
  151. #endif
  152. strlcpy( hostname, inet_ntoa( Addr->sin_addr ), sizeof( hostname ));
  153. } else {
  154. strlcpy( hostname, h->h_name, sizeof( hostname ));
  155. h = gethostbyname( hostname );
  156. if ( h ) {
  157. if (memcmp(h->h_addr, &Addr->sin_addr, sizeof (struct in_addr))) {
  158. addr = (struct in_addr*) h->h_addr;
  159. strlcpy(ipstr, inet_ntoa(*addr), sizeof ipstr);
  160. ntoaptr = inet_ntoa( Addr->sin_addr );
  161. Log(LOG_WARNING,"Possible forgery: %s resolved to %s (which is at ip %s!)",
  162. ntoaptr, hostname, ipstr);
  163. strlcpy( hostname, ntoaptr, sizeof hostname);
  164. }
  165. } else {
  166. ntoaptr = inet_ntoa( Addr->sin_addr );
  167. Log(LOG_WARNING, "Possible forgery: %s resolved to %s (which has no ip address)",
  168. ntoaptr, hostname);
  169. strlcpy( hostname, ntoaptr, sizeof hostname);
  170. }
  171. }
  172. Log_Resolver( LOG_DEBUG, "Ok, translated %s to \"%s\".", inet_ntoa( Addr->sin_addr ), hostname );
  173. len = strlen( hostname );
  174. hostname[len] = '\n'; len++;
  175. if (!array_copyb(&resolved_addr, hostname, len )) {
  176. Log_Resolver( LOG_CRIT, "Resolver: Can't copy resolved name: %s!", strerror( errno ));
  177. close( w_fd );
  178. return;
  179. }
  180. #ifdef IDENTAUTH
  181. assert(identsock >= 0);
  182. if (identsock >= 0) {
  183. /* Do "IDENT" (aka "AUTH") lookup and append result to resolved_addr array */
  184. #ifdef DEBUG
  185. Log_Resolver( LOG_DEBUG, "Doing IDENT lookup on socket %d ...", identsock );
  186. #endif
  187. res = ident_id( identsock, 10 );
  188. #ifdef DEBUG
  189. Log_Resolver(LOG_DEBUG, "Ok, IDENT lookup on socket %d done: \"%s\"",
  190. identsock, res ? res : "(NULL)" );
  191. #endif
  192. if (res && !array_cats(&resolved_addr, res)) {
  193. Log_Resolver(LOG_WARNING, "Resolver: Cannot copy IDENT result: %s!", strerror(errno));
  194. /* omit ident and return hostname only */
  195. }
  196. if (res) free(res);
  197. }
  198. #else
  199. (void)identsock;
  200. #endif
  201. len = array_bytes(&resolved_addr);
  202. if( (size_t)write( w_fd, array_start(&resolved_addr), len) != len )
  203. Log_Resolver( LOG_CRIT, "Resolver: Can't write result to parent: %s!", strerror( errno ));
  204. close(w_fd);
  205. array_free(&resolved_addr);
  206. } /* Do_ResolveAddr */
  207. static void
  208. Do_ResolveName( const char *Host, int w_fd )
  209. {
  210. /* Resolver sub-process: resolve name and write result into pipe
  211. * to parent. */
  212. char ip[16];
  213. struct hostent *h;
  214. struct in_addr *addr;
  215. size_t len;
  216. Log_Resolver( LOG_DEBUG, "Now resolving \"%s\" ...", Host );
  217. /* Resolve hostname */
  218. h = gethostbyname( Host );
  219. if( h ) {
  220. addr = (struct in_addr *)h->h_addr;
  221. strlcpy( ip, inet_ntoa( *addr ), sizeof( ip ));
  222. } else {
  223. #ifdef h_errno
  224. Log_Resolver( LOG_WARNING, "Can't resolve \"%s\": %s!", Host, Get_Error( h_errno ));
  225. #else
  226. Log_Resolver( LOG_WARNING, "Can't resolve \"%s\"!", Host );
  227. #endif
  228. close(w_fd);
  229. return;
  230. }
  231. #ifdef DEBUG
  232. Log_Resolver( LOG_DEBUG, "Ok, translated \"%s\" to %s.", Host, ip );
  233. #endif
  234. /* Write result into pipe to parent */
  235. len = strlen( ip );
  236. if ((size_t)write( w_fd, ip, len ) != len) {
  237. Log_Resolver( LOG_CRIT, "Resolver: Can't write to parent: %s!", strerror( errno ));
  238. close( w_fd );
  239. }
  240. } /* Do_ResolveName */
  241. #ifdef h_errno
  242. static char *
  243. Get_Error( int H_Error )
  244. {
  245. /* Get error message for H_Error */
  246. switch( H_Error )
  247. {
  248. case HOST_NOT_FOUND:
  249. return "host not found";
  250. case NO_DATA:
  251. return "name valid but no IP address defined";
  252. case NO_RECOVERY:
  253. return "name server error";
  254. case TRY_AGAIN:
  255. return "name server temporary not available";
  256. default:
  257. return "unknown error";
  258. }
  259. } /* Get_Error */
  260. #endif
  261. static bool
  262. register_callback( RES_STAT *s, void (*cbfunc)(int, short))
  263. {
  264. assert(cbfunc != NULL);
  265. assert(s != NULL);
  266. assert(s->resolver_fd >= 0);
  267. if (io_setnonblock(s->resolver_fd) &&
  268. io_event_create(s->resolver_fd, IO_WANTREAD, cbfunc))
  269. return true;
  270. Log( LOG_CRIT, "Resolver: Could not register callback function: %s!", strerror(errno));
  271. close(s->resolver_fd);
  272. Resolve_Init(s);
  273. return false;
  274. }
  275. GLOBAL bool
  276. Resolve_Shutdown( RES_STAT *s)
  277. {
  278. bool ret = false;
  279. assert(s != NULL);
  280. assert(s->resolver_fd >= 0);
  281. if (s->resolver_fd >= 0)
  282. ret = io_close(s->resolver_fd);
  283. Resolve_Init(s);
  284. return ret;
  285. }
  286. /**
  287. * Read result of resolver sub-process from pipe
  288. */
  289. GLOBAL size_t
  290. Resolve_Read( RES_STAT *s, void* readbuf, size_t buflen)
  291. {
  292. ssize_t bytes_read;
  293. assert(buflen > 0);
  294. /* Read result from pipe */
  295. bytes_read = read(s->resolver_fd, readbuf, buflen);
  296. if (bytes_read < 0) {
  297. if (errno == EAGAIN)
  298. return 0;
  299. Log( LOG_CRIT, "Resolver: Can't read result: %s!", strerror(errno));
  300. bytes_read = 0;
  301. }
  302. #ifdef DEBUG
  303. else if (bytes_read == 0)
  304. Log( LOG_DEBUG, "Resolver: Can't read result: EOF");
  305. #endif
  306. Resolve_Shutdown(s);
  307. return (size_t)bytes_read;
  308. }
  309. /* -eof- */