resolve.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  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.12.2.1 2005/09/02 22:07:38 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. #ifdef IDENTAUTH
  36. LOCAL void Do_ResolveAddr PARAMS(( struct sockaddr_in *Addr, int Sock, int w_fd ));
  37. #else
  38. LOCAL void Do_ResolveAddr PARAMS(( struct sockaddr_in *Addr, int w_fd ));
  39. #endif
  40. LOCAL void Do_ResolveName PARAMS(( char *Host, int w_fd ));
  41. #ifdef h_errno
  42. LOCAL char *Get_Error PARAMS(( int H_Error ));
  43. #endif
  44. LOCAL RES_STAT *New_Res_Stat PARAMS(( void ));
  45. GLOBAL void
  46. Resolve_Init( void )
  47. {
  48. /* Initialize module */
  49. FD_ZERO( &Resolver_FDs );
  50. } /* Resolve_Init */
  51. #ifdef IDENTAUTH
  52. GLOBAL RES_STAT *
  53. Resolve_Addr( struct sockaddr_in *Addr, int Sock )
  54. #else
  55. GLOBAL RES_STAT *
  56. Resolve_Addr( struct sockaddr_in *Addr )
  57. #endif
  58. {
  59. /* Resolve IP (asynchronous!). On errors, e.g. if the child process
  60. * can't be forked, this functions returns NULL. */
  61. RES_STAT *s;
  62. int pid;
  63. s = New_Res_Stat( );
  64. if( ! s ) return NULL;
  65. /* For sub-process */
  66. pid = fork( );
  67. if( pid > 0 )
  68. {
  69. /* Main process */
  70. Log( LOG_DEBUG, "Resolver for %s created (PID %d).", inet_ntoa( Addr->sin_addr ), pid );
  71. FD_SET( s->pipe[0], &Resolver_FDs );
  72. if( s->pipe[0] > Conn_MaxFD ) Conn_MaxFD = s->pipe[0];
  73. s->pid = pid;
  74. return s;
  75. }
  76. else if( pid == 0 )
  77. {
  78. /* Sub process */
  79. Log_Init_Resolver( );
  80. #ifdef IDENTAUTH
  81. Do_ResolveAddr( Addr, Sock, s->pipe[1] );
  82. #else
  83. Do_ResolveAddr( Addr, s->pipe[1] );
  84. #endif
  85. Log_Exit_Resolver( );
  86. exit( 0 );
  87. }
  88. else
  89. {
  90. /* Error! */
  91. close(s->pipe[0]);
  92. close(s->pipe[1]);
  93. free( s );
  94. Log( LOG_CRIT, "Resolver: Can't fork: %s!", strerror( errno ));
  95. return NULL;
  96. }
  97. } /* Resolve_Addr */
  98. GLOBAL RES_STAT *
  99. Resolve_Name( char *Host )
  100. {
  101. /* Resolve hostname (asynchronous!). On errors, e.g. if the child
  102. * process can't be forked, this functions returns NULL. */
  103. RES_STAT *s;
  104. int pid;
  105. s = New_Res_Stat( );
  106. if( ! s ) return NULL;
  107. /* Fork sub-process */
  108. pid = fork( );
  109. if( pid > 0 )
  110. {
  111. /* Main process */
  112. Log( LOG_DEBUG, "Resolver for \"%s\" created (PID %d).", Host, pid );
  113. FD_SET( s->pipe[0], &Resolver_FDs );
  114. if( s->pipe[0] > Conn_MaxFD ) Conn_MaxFD = s->pipe[0];
  115. s->pid = pid;
  116. return s;
  117. }
  118. else if( pid == 0 )
  119. {
  120. /* Sub process */
  121. Log_Init_Resolver( );
  122. Do_ResolveName( Host, s->pipe[1] );
  123. Log_Exit_Resolver( );
  124. exit( 0 );
  125. }
  126. else
  127. {
  128. /* Error! */
  129. close(s->pipe[0]);
  130. close(s->pipe[1]);
  131. free( s );
  132. Log( LOG_CRIT, "Resolver: Can't fork: %s!", strerror( errno ));
  133. return NULL;
  134. }
  135. } /* Resolve_Name */
  136. #ifdef IDENTAUTH
  137. LOCAL void
  138. Do_ResolveAddr( struct sockaddr_in *Addr, int Sock, int w_fd )
  139. #else
  140. LOCAL void
  141. Do_ResolveAddr( struct sockaddr_in *Addr, int w_fd )
  142. #endif
  143. {
  144. /* Resolver sub-process: resolve IP address and write result into
  145. * pipe to parent. */
  146. char hostname[HOST_LEN];
  147. struct hostent *h;
  148. size_t len;
  149. #ifdef IDENTAUTH
  150. char *res;
  151. #endif
  152. /* Resolve IP address */
  153. Log_Resolver( LOG_DEBUG, "Now resolving %s ...", inet_ntoa( Addr->sin_addr ));
  154. h = gethostbyaddr( (char *)&Addr->sin_addr, sizeof( Addr->sin_addr ), AF_INET );
  155. if( h ) strlcpy( hostname, h->h_name, sizeof( hostname ));
  156. else
  157. {
  158. #ifdef h_errno
  159. Log_Resolver( LOG_WARNING, "Can't resolve address \"%s\": %s!", inet_ntoa( Addr->sin_addr ), Get_Error( h_errno ));
  160. #else
  161. Log_Resolver( LOG_WARNING, "Can't resolve address \"%s\"!", inet_ntoa( Addr->sin_addr ));
  162. #endif
  163. strlcpy( hostname, inet_ntoa( Addr->sin_addr ), sizeof( hostname ));
  164. }
  165. Log_Resolver( LOG_DEBUG, "Ok, translated %s to \"%s\".", inet_ntoa( Addr->sin_addr ), hostname );
  166. /* Write resolver result into pipe to parent */
  167. len = strlen( hostname );
  168. hostname[len] = '\n'; len++;
  169. if( (size_t)write( w_fd, hostname, len ) != (size_t)len )
  170. {
  171. Log_Resolver( LOG_CRIT, "Resolver: Can't write to parent: %s!", strerror( errno ));
  172. close( w_fd );
  173. return;
  174. }
  175. #ifdef IDENTAUTH
  176. /* Do "IDENT" (aka "AUTH") lookup and write result to parent */
  177. Log_Resolver( LOG_DEBUG, "Doing IDENT lookup on socket %d ...", Sock );
  178. res = ident_id( Sock, 10 );
  179. Log_Resolver( LOG_DEBUG, "Ok, IDENT lookup on socket %d done: \"%s\"", Sock, res ? res : "" );
  180. /* Write IDENT result into pipe to parent */
  181. if (res) {
  182. len = strlen(res);
  183. res[len] = '\n';
  184. len++;
  185. } else len = 1;
  186. if( (size_t)write( w_fd, res ? res : "\n", len ) != (size_t)len )
  187. {
  188. Log_Resolver( LOG_CRIT, "Resolver: Can't write to parent (IDENT): %s!", strerror( errno ));
  189. close( w_fd );
  190. }
  191. free( res );
  192. #endif
  193. } /* Do_ResolveAddr */
  194. LOCAL void
  195. Do_ResolveName( char *Host, int w_fd )
  196. {
  197. /* Resolver sub-process: resolve name and write result into pipe
  198. * to parent. */
  199. char ip[16];
  200. struct hostent *h;
  201. struct in_addr *addr;
  202. int len;
  203. Log_Resolver( LOG_DEBUG, "Now resolving \"%s\" ...", Host );
  204. /* Resolve hostname */
  205. h = gethostbyname( Host );
  206. if( h )
  207. {
  208. addr = (struct in_addr *)h->h_addr;
  209. strlcpy( ip, inet_ntoa( *addr ), sizeof( ip ));
  210. }
  211. else
  212. {
  213. #ifdef h_errno
  214. Log_Resolver( LOG_WARNING, "Can't resolve \"%s\": %s!", Host, Get_Error( h_errno ));
  215. #else
  216. Log_Resolver( LOG_WARNING, "Can't resolve \"%s\"!", Host );
  217. #endif
  218. ip[0] = '\0';
  219. }
  220. if( ip[0] ) Log_Resolver( LOG_DEBUG, "Ok, translated \"%s\" to %s.", Host, ip );
  221. /* Write result into pipe to parent */
  222. len = strlen( ip );
  223. ip[len] = '\n'; len++;
  224. if( (size_t)write( w_fd, ip, len ) != (size_t)len )
  225. {
  226. Log_Resolver( LOG_CRIT, "Resolver: Can't write to parent: %s!", strerror( errno ));
  227. close( w_fd );
  228. }
  229. } /* Do_ResolveName */
  230. #ifdef h_errno
  231. LOCAL char *
  232. Get_Error( int H_Error )
  233. {
  234. /* Get error message for H_Error */
  235. switch( H_Error )
  236. {
  237. case HOST_NOT_FOUND:
  238. return "host not found";
  239. case NO_DATA:
  240. return "name valid but no IP address defined";
  241. case NO_RECOVERY:
  242. return "name server error";
  243. case TRY_AGAIN:
  244. return "name server temporary not available";
  245. default:
  246. return "unknown error";
  247. }
  248. } /* Get_Error */
  249. #endif
  250. LOCAL RES_STAT *
  251. New_Res_Stat( void )
  252. {
  253. RES_STAT *s;
  254. /* Allocate memory */
  255. s = (RES_STAT *)malloc( sizeof( RES_STAT ));
  256. if( ! s )
  257. {
  258. Log( LOG_EMERG, "Resolver: Can't allocate memory! [Resolve_Addr]" );
  259. return NULL;
  260. }
  261. /* Initialize pipe for result */
  262. if( pipe( s->pipe ) != 0 )
  263. {
  264. free( s );
  265. Log( LOG_ALERT, "Resolver: Can't create output pipe: %s!", strerror( errno ));
  266. return NULL;
  267. }
  268. s->stage = 0;
  269. s->bufpos = 0;
  270. s->pid = -1;
  271. return s;
  272. } /* New_Res_Stat */
  273. /* -eof- */