2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001-2003 by Alexander Barton (alex@barton.de)
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.
11 * Asynchronous resolver
17 static char UNUSED id[] = "$Id: resolve.c,v 1.23 2006/02/08 15:24:10 fw Exp $";
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
45 static void Do_ResolveAddr PARAMS(( struct sockaddr_in *Addr, int Sock, int w_fd ));
46 static void Do_ResolveName PARAMS(( const char *Host, int w_fd ));
47 static bool register_callback PARAMS((RES_STAT *s, void (*cbfunc)(int, short)));
50 static char *Get_Error PARAMS(( int H_Error ));
54 Resolver_fork(int *pipefds)
57 if (pipe(pipefds) != 0) {
58 Log( LOG_ALERT, "Resolver: Can't create output pipe: %s!", strerror( errno ));
65 Log( LOG_CRIT, "Resolver: Can't fork: %s!", strerror( errno ));
81 Resolve_Addr( RES_STAT *s, struct sockaddr_in *Addr, int identsock, void (*cbfunc)(int, short))
83 /* Resolve IP (asynchronous!). */
87 pid = Resolver_fork(pipefd);
90 Log( LOG_DEBUG, "Resolver for %s created (PID %d).", inet_ntoa( Addr->sin_addr ), pid );
93 s->resolver_fd = pipefd[0];
94 return register_callback(s, cbfunc);
95 } else if( pid == 0 ) {
97 Do_ResolveAddr( Addr, identsock, pipefd[1]);
106 Resolve_Name( RES_STAT *s, const char *Host, void (*cbfunc)(int, short))
108 /* Resolve hostname (asynchronous!). */
112 pid = Resolver_fork(pipefd);
116 Log( LOG_DEBUG, "Resolver for \"%s\" created (PID %d).", Host, pid );
119 s->resolver_fd = pipefd[0];
120 return register_callback(s, cbfunc);
121 } else if( pid == 0 ) {
123 Do_ResolveName(Host, pipefd[1]);
124 Log_Exit_Resolver( );
132 Resolve_Init(RES_STAT *s)
141 Do_ResolveAddr( struct sockaddr_in *Addr, int identsock, int w_fd )
143 /* Resolver sub-process: resolve IP address and write result into
146 char hostname[HOST_LEN];
147 char ipstr[HOST_LEN];
150 struct in_addr *addr;
156 array_init(&resolved_addr);
157 /* Resolve IP address */
159 Log_Resolver( LOG_DEBUG, "Now resolving %s ...", inet_ntoa( Addr->sin_addr ));
161 h = gethostbyaddr( (char *)&Addr->sin_addr, sizeof( Addr->sin_addr ), AF_INET );
164 Log_Resolver( LOG_WARNING, "Can't resolve address \"%s\": %s!", inet_ntoa( Addr->sin_addr ), Get_Error( h_errno ));
166 Log_Resolver( LOG_WARNING, "Can't resolve address \"%s\"!", inet_ntoa( Addr->sin_addr ));
168 strlcpy( hostname, inet_ntoa( Addr->sin_addr ), sizeof( hostname ));
170 strlcpy( hostname, h->h_name, sizeof( hostname ));
172 h = gethostbyname( hostname );
174 if (memcmp(h->h_addr, &Addr->sin_addr, sizeof (struct in_addr))) {
175 addr = (struct in_addr*) h->h_addr;
176 strlcpy(ipstr, inet_ntoa(*addr), sizeof ipstr);
177 ntoaptr = inet_ntoa( Addr->sin_addr );
178 Log(LOG_WARNING,"Possible forgery: %s resolved to %s (which is at ip %s!)",
179 ntoaptr, hostname, ipstr);
180 strlcpy( hostname, ntoaptr, sizeof hostname);
183 ntoaptr = inet_ntoa( Addr->sin_addr );
184 Log(LOG_WARNING, "Possible forgery: %s resolved to %s (which has no ip address)",
186 strlcpy( hostname, ntoaptr, sizeof hostname);
189 Log_Resolver( LOG_DEBUG, "Ok, translated %s to \"%s\".", inet_ntoa( Addr->sin_addr ), hostname );
191 len = strlen( hostname );
192 hostname[len] = '\n'; len++;
193 if (!array_copyb(&resolved_addr, hostname, len )) {
194 Log_Resolver( LOG_CRIT, "Resolver: Can't copy resolved name: %s!", strerror( errno ));
200 assert(identsock >= 0);
201 if (identsock >= 0) {
202 /* Do "IDENT" (aka "AUTH") lookup and append result to resolved_addr array */
204 Log_Resolver( LOG_DEBUG, "Doing IDENT lookup on socket %d ...", identsock );
206 res = ident_id( identsock, 10 );
208 Log_Resolver(LOG_DEBUG, "Ok, IDENT lookup on socket %d done: \"%s\"",
209 identsock, res ? res : "(NULL)" );
211 if (res && !array_cats(&resolved_addr, res)) {
212 Log_Resolver(LOG_WARNING, "Resolver: Cannot copy IDENT result: %s!", strerror(errno));
213 /* omit ident and return hostname only */
221 len = array_bytes(&resolved_addr);
222 if( (size_t)write( w_fd, array_start(&resolved_addr), len) != len )
223 Log_Resolver( LOG_CRIT, "Resolver: Can't write result to parent: %s!", strerror( errno ));
226 array_free(&resolved_addr);
227 } /* Do_ResolveAddr */
231 Do_ResolveName( const char *Host, int w_fd )
233 /* Resolver sub-process: resolve name and write result into pipe
238 struct in_addr *addr;
241 Log_Resolver( LOG_DEBUG, "Now resolving \"%s\" ...", Host );
243 /* Resolve hostname */
244 h = gethostbyname( Host );
246 addr = (struct in_addr *)h->h_addr;
247 strlcpy( ip, inet_ntoa( *addr ), sizeof( ip ));
250 Log_Resolver( LOG_WARNING, "Can't resolve \"%s\": %s!", Host, Get_Error( h_errno ));
252 Log_Resolver( LOG_WARNING, "Can't resolve \"%s\"!", Host );
258 Log_Resolver( LOG_DEBUG, "Ok, translated \"%s\" to %s.", Host, ip );
260 /* Write result into pipe to parent */
262 if( write( w_fd, ip, len ) != len) {
263 Log_Resolver( LOG_CRIT, "Resolver: Can't write to parent: %s!", strerror( errno ));
266 } /* Do_ResolveName */
272 Get_Error( int H_Error )
274 /* Get error message for H_Error */
279 return "host not found";
281 return "name valid but no IP address defined";
283 return "name server error";
285 return "name server temporary not available";
287 return "unknown error";
295 register_callback( RES_STAT *s, void (*cbfunc)(int, short))
299 assert(s->resolver_fd >= 0);
301 if (io_setnonblock(s->resolver_fd) &&
302 io_event_create(s->resolver_fd, IO_WANTREAD, cbfunc))
305 Log( LOG_CRIT, "Resolver: Could not register callback function: %s!", strerror(errno));
312 Resolve_Shutdown( RES_STAT *s)
317 assert(s->resolver_fd >= 0);
319 if (s->resolver_fd >= 0)
320 ret = io_close(s->resolver_fd);
328 Resolve_Read( RES_STAT *s, void* readbuf, size_t buflen)
330 /* Read result of resolver sub-process from pipe */
334 /* Read result from pipe */
336 bytes_read = read(s->resolver_fd, readbuf, buflen);
337 if (bytes_read < 0) {
338 if (errno != EAGAIN) {
340 Log( LOG_CRIT, "Resolver: Can't read result: %s!", strerror(err));
349 if (bytes_read == 0) { /* EOF: lookup failed */
351 Log( LOG_DEBUG, "Resolver: Can't read result: EOF");