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.21 2005/09/12 19:10:20 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!). */
88 pid = Resolver_fork(pipefd);
91 Log( LOG_DEBUG, "Resolver for %s created (PID %d).", inet_ntoa( Addr->sin_addr ), pid );
94 s->resolver_fd = pipefd[0];
95 return register_callback(s, cbfunc);
96 } else if( pid == 0 ) {
98 Do_ResolveAddr( Addr, identsock, pipefd[1]);
107 Resolve_Name( RES_STAT *s, const char *Host, void (*cbfunc)(int, short))
109 /* Resolve hostname (asynchronous!). */
114 pid = Resolver_fork(pipefd);
118 Log( LOG_DEBUG, "Resolver for \"%s\" created (PID %d).", Host, pid );
121 s->resolver_fd = pipefd[0];
122 return register_callback(s, cbfunc);
123 } else if( pid == 0 ) {
125 Do_ResolveName(Host, pipefd[1]);
126 Log_Exit_Resolver( );
134 Resolve_Init(RES_STAT *s)
139 /* s->success must not be changed -- it will be set by other Resolve_*() functions */
144 Do_ResolveAddr( struct sockaddr_in *Addr, int identsock, int w_fd )
146 /* Resolver sub-process: resolve IP address and write result into
149 char hostname[HOST_LEN];
150 char ipstr[HOST_LEN];
153 struct in_addr *addr;
159 array_init(&resolved_addr);
160 /* Resolve IP address */
162 Log_Resolver( LOG_DEBUG, "Now resolving %s ...", inet_ntoa( Addr->sin_addr ));
164 h = gethostbyaddr( (char *)&Addr->sin_addr, sizeof( Addr->sin_addr ), AF_INET );
167 Log_Resolver( LOG_WARNING, "Can't resolve address \"%s\": %s!", inet_ntoa( Addr->sin_addr ), Get_Error( h_errno ));
169 Log_Resolver( LOG_WARNING, "Can't resolve address \"%s\"!", inet_ntoa( Addr->sin_addr ));
171 strlcpy( hostname, inet_ntoa( Addr->sin_addr ), sizeof( hostname ));
173 strlcpy( hostname, h->h_name, sizeof( hostname ));
175 h = gethostbyname( hostname );
177 if (memcmp(h->h_addr, &Addr->sin_addr, sizeof (struct in_addr))) {
178 addr = (struct in_addr*) h->h_addr;
179 strlcpy(ipstr, inet_ntoa(*addr), sizeof ipstr);
180 ntoaptr = inet_ntoa( Addr->sin_addr );
181 Log(LOG_WARNING,"Possible forgery: %s resolved to %s (which is at ip %s!)",
182 ntoaptr, hostname, ipstr);
183 strlcpy( hostname, ntoaptr, sizeof hostname);
186 ntoaptr = inet_ntoa( Addr->sin_addr );
187 Log(LOG_WARNING, "Possible forgery: %s resolved to %s (which has no ip address)",
189 strlcpy( hostname, ntoaptr, sizeof hostname);
192 Log_Resolver( LOG_DEBUG, "Ok, translated %s to \"%s\".", inet_ntoa( Addr->sin_addr ), hostname );
194 len = strlen( hostname );
195 hostname[len] = '\n'; len++;
196 if (!array_copyb(&resolved_addr, hostname, len )) {
197 Log_Resolver( LOG_CRIT, "Resolver: Can't copy resolved name: %s!", strerror( errno ));
203 assert(identsock >= 0);
204 if (identsock >= 0) {
205 /* Do "IDENT" (aka "AUTH") lookup and append result to resolved_addr array */
207 Log_Resolver( LOG_DEBUG, "Doing IDENT lookup on socket %d ...", identsock );
209 res = ident_id( identsock, 10 );
211 Log_Resolver(LOG_DEBUG, "Ok, IDENT lookup on socket %d done: \"%s\"",
212 identsock, res ? res : "(NULL)" );
214 if (res && !array_cats(&resolved_addr, res)) {
215 Log_Resolver(LOG_WARNING, "Resolver: Cannot copy IDENT result: %s!", strerror(errno));
216 /* omit ident and return hostname only */
224 len = array_bytes(&resolved_addr);
225 if( (size_t)write( w_fd, array_start(&resolved_addr), len) != len )
226 Log_Resolver( LOG_CRIT, "Resolver: Can't write result to parent: %s!", strerror( errno ));
229 array_free(&resolved_addr);
230 } /* Do_ResolveAddr */
234 Do_ResolveName( const char *Host, int w_fd )
236 /* Resolver sub-process: resolve name and write result into pipe
241 struct in_addr *addr;
244 Log_Resolver( LOG_DEBUG, "Now resolving \"%s\" ...", Host );
246 /* Resolve hostname */
247 h = gethostbyname( Host );
249 addr = (struct in_addr *)h->h_addr;
250 strlcpy( ip, inet_ntoa( *addr ), sizeof( ip ));
253 Log_Resolver( LOG_WARNING, "Can't resolve \"%s\": %s!", Host, Get_Error( h_errno ));
255 Log_Resolver( LOG_WARNING, "Can't resolve \"%s\"!", Host );
261 Log_Resolver( LOG_DEBUG, "Ok, translated \"%s\" to %s.", Host, ip );
263 /* Write result into pipe to parent */
265 ip[len] = '\n'; len++;
266 if( (size_t)write( w_fd, ip, len ) != (size_t)len ) {
267 Log_Resolver( LOG_CRIT, "Resolver: Can't write to parent: %s!", strerror( errno ));
270 } /* Do_ResolveName */
276 Get_Error( int H_Error )
278 /* Get error message for H_Error */
283 return "host not found";
285 return "name valid but no IP address defined";
287 return "name server error";
289 return "name server temporary not available";
291 return "unknown error";
299 register_callback( RES_STAT *s, void (*cbfunc)(int, short))
303 assert(s->resolver_fd >= 0);
305 if (io_setnonblock(s->resolver_fd) &&
306 io_event_create(s->resolver_fd, IO_WANTREAD, cbfunc))
309 Log( LOG_CRIT, "Resolver: Could not register callback function: %s!", strerror(errno));
316 Resolve_Shutdown( RES_STAT *s)
321 assert(s->resolver_fd >= 0);
323 if (s->resolver_fd >= 0)
324 ret = io_close(s->resolver_fd);
332 Resolve_Read( RES_STAT *s, void* readbuf, size_t buflen)
334 /* Read result of resolver sub-process from pipe */
338 /* Read result from pipe */
340 bytes_read = read(s->resolver_fd, readbuf, buflen);
341 if (bytes_read < 0) {
342 if (errno != EAGAIN) {
344 Log( LOG_CRIT, "Resolver: Can't read result: %s!", strerror(err));
353 if (bytes_read == 0) { /* EOF: lookup failed */
355 Log( LOG_DEBUG, "Resolver: Can't read result: EOF");