]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/resolve.c
Fixed resolver when using IDENT lookups, cleaned up code.
[ngircd-alex.git] / src / ngircd / resolve.c
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
14
15 #include "portab.h"
16
17 static char UNUSED id[] = "$Id: resolve.c,v 1.9 2004/05/11 00:01:11 alex Exp $";
18
19 #include "imp.h"
20 #include <assert.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <netdb.h>
29
30 #ifdef IDENTAUTH
31 #ifdef HAVE_IDENT_H
32 #include <ident.h>
33 #endif
34 #endif
35
36 #include "conn.h"
37 #include "defines.h"
38 #include "log.h"
39
40 #include "exp.h"
41 #include "resolve.h"
42
43
44 #ifdef IDENTAUTH
45 LOCAL VOID Do_ResolveAddr PARAMS(( struct sockaddr_in *Addr, INT Sock, INT w_fd ));
46 #else
47 LOCAL VOID Do_ResolveAddr PARAMS(( struct sockaddr_in *Addr, INT w_fd ));
48 #endif
49
50 LOCAL VOID Do_ResolveName PARAMS(( CHAR *Host, INT w_fd ));
51
52 #ifdef h_errno
53 LOCAL CHAR *Get_Error PARAMS(( INT H_Error ));
54 #endif
55
56
57 GLOBAL VOID
58 Resolve_Init( VOID )
59 {
60         /* Initialize module */
61
62         FD_ZERO( &Resolver_FDs );
63 } /* Resolve_Init */
64
65
66 #ifdef IDENTAUTH
67 GLOBAL RES_STAT *
68 Resolve_Addr( struct sockaddr_in *Addr, int Sock )
69 #else
70 GLOBAL RES_STAT *
71 Resolve_Addr( struct sockaddr_in *Addr )
72 #endif
73 {
74         /* Resolve IP (asynchronous!). On errors, e.g. if the child process
75          * can't be forked, this functions returns NULL. */
76
77         RES_STAT *s;
78         INT pid;
79
80         /* Allocate memory */
81         s = (RES_STAT *)malloc( sizeof( RES_STAT ));
82         if( ! s )
83         {
84                 Log( LOG_EMERG, "Resolver: Can't allocate memory! [Resolve_Addr]" );
85                 return NULL;
86         }
87
88         /* Initialize pipe for result */
89         if( pipe( s->pipe ) != 0 )
90         {
91                 free( s );
92                 Log( LOG_ALERT, "Resolver: Can't create output pipe: %s!", strerror( errno ));
93                 return NULL;
94         }
95
96         /* For sub-process */
97         pid = fork( );
98         if( pid > 0 )
99         {
100                 /* Main process */
101                 Log( LOG_DEBUG, "Resolver for %s created (PID %d).", inet_ntoa( Addr->sin_addr ), pid );
102                 FD_SET( s->pipe[0], &Resolver_FDs );
103                 if( s->pipe[0] > Conn_MaxFD ) Conn_MaxFD = s->pipe[0];
104                 s->pid = pid;
105                 s->stage = 0;
106                 s->bufpos = 0;
107                 return s;
108         }
109         else if( pid == 0 )
110         {
111                 /* Sub process */
112                 Log_Init_Resolver( );
113 #ifdef IDENTAUTH
114                 Do_ResolveAddr( Addr, Sock, s->pipe[1] );
115 #else
116                 Do_ResolveAddr( Addr, s->pipe[1] );
117 #endif
118                 Log_Exit_Resolver( );
119                 exit( 0 );
120         }
121         else
122         {
123                 /* Error! */
124                 free( s );
125                 Log( LOG_CRIT, "Resolver: Can't fork: %s!", strerror( errno ));
126                 return NULL;
127         }
128 } /* Resolve_Addr */
129
130
131 GLOBAL RES_STAT *
132 Resolve_Name( CHAR *Host )
133 {
134         /* Resolve hostname (asynchronous!). On errors, e.g. if the child
135          * process can't be forked, this functions returns NULL. */
136
137         RES_STAT *s;
138         INT pid;
139
140         /* Allocate memory */
141         s = (RES_STAT *)malloc( sizeof( RES_STAT ));
142         if( ! s )
143         {
144                 Log( LOG_EMERG, "Resolver: Can't allocate memory! [Resolve_Name]" );
145                 return NULL;
146         }
147
148         /* Initialize the pipe for the result */
149         if( pipe( s->pipe ) != 0 )
150         {
151                 free( s );
152                 Log( LOG_ALERT, "Resolver: Can't create output pipe: %s!", strerror( errno ));
153                 return NULL;
154         }
155
156         /* Fork sub-process */
157         pid = fork( );
158         if( pid > 0 )
159         {
160                 /* Main process */
161                 Log( LOG_DEBUG, "Resolver for \"%s\" created (PID %d).", Host, pid );
162                 FD_SET( s->pipe[0], &Resolver_FDs );
163                 if( s->pipe[0] > Conn_MaxFD ) Conn_MaxFD = s->pipe[0];
164                 s->pid = pid;
165                 s->stage = 0;
166                 s->bufpos = 0;
167                 return s;
168         }
169         else if( pid == 0 )
170         {
171                 /* Sub process */
172                 Log_Init_Resolver( );
173                 Do_ResolveName( Host, s->pipe[1] );
174                 Log_Exit_Resolver( );
175                 exit( 0 );
176         }
177         else
178         {
179                 /* Error! */
180                 free( s );
181                 Log( LOG_CRIT, "Resolver: Can't fork: %s!", strerror( errno ));
182                 return NULL;
183         }
184 } /* Resolve_Name */
185
186
187 #ifdef IDENTAUTH
188 LOCAL VOID
189 Do_ResolveAddr( struct sockaddr_in *Addr, int Sock, INT w_fd )
190 #else
191 LOCAL VOID
192 Do_ResolveAddr( struct sockaddr_in *Addr, INT w_fd )
193 #endif
194 {
195         /* Resolver sub-process: resolve IP address and write result into
196          * pipe to parent. */
197
198         CHAR hostname[HOST_LEN];
199         struct hostent *h;
200         INT len;
201 #ifdef IDENTAUTH
202         CHAR *res;
203 #endif
204
205         /* Resolve IP address */
206         Log_Resolver( LOG_DEBUG, "Now resolving %s ...", inet_ntoa( Addr->sin_addr ));
207         h = gethostbyaddr( (CHAR *)&Addr->sin_addr, sizeof( Addr->sin_addr ), AF_INET );
208         if( h ) strlcpy( hostname, h->h_name, sizeof( hostname ));
209         else
210         {
211 #ifdef h_errno
212                 Log_Resolver( LOG_WARNING, "Can't resolve address \"%s\": %s!", inet_ntoa( Addr->sin_addr ), Get_Error( h_errno ));
213 #else
214                 Log_Resolver( LOG_WARNING, "Can't resolve address \"%s\"!", inet_ntoa( Addr->sin_addr ));
215 #endif  
216                 strlcpy( hostname, inet_ntoa( Addr->sin_addr ), sizeof( hostname ));
217         }
218         Log_Resolver( LOG_DEBUG, "Ok, translated %s to \"%s\".", inet_ntoa( Addr->sin_addr ), hostname );
219
220         /* Write resolver result into pipe to parent */
221         len = strlen( hostname ); 
222         hostname[len] = '\n'; len++;
223         if( (size_t)write( w_fd, hostname, len ) != (size_t)len )
224         {
225                 Log_Resolver( LOG_CRIT, "Resolver: Can't write to parent: %s!", strerror( errno ));
226                 close( w_fd );
227                 return;
228         }
229
230 #ifdef IDENTAUTH
231         /* Do "IDENT" (aka "AUTH") lookup and write result to parent */
232         Log_Resolver( LOG_DEBUG, "Doing IDENT lookup on socket %d ...", Sock );
233         res = ident_id( Sock, 10 );
234         Log_Resolver( LOG_DEBUG, "Ok, IDENT lookup on socket %d done: \"%s\"", Sock, res ? res : "" );
235
236         /* Write IDENT result into pipe to parent */
237         len = strlen( res ? res : "" );
238         if( res != NULL ) res[len] = '\n';
239         len++;
240         if( (size_t)write( w_fd, res ? res : "\n", len ) != (size_t)len )
241         {
242                 Log_Resolver( LOG_CRIT, "Resolver: Can't write to parent (IDENT): %s!", strerror( errno ));
243                 close( w_fd );
244         }
245         free( res );
246 #endif
247 } /* Do_ResolveAddr */
248
249
250 LOCAL VOID
251 Do_ResolveName( CHAR *Host, INT w_fd )
252 {
253         /* Resolver sub-process: resolve name and write result into pipe
254          * to parent. */
255
256         CHAR ip[16];
257         struct hostent *h;
258         struct in_addr *addr;
259         INT len;
260
261         Log_Resolver( LOG_DEBUG, "Now resolving \"%s\" ...", Host );
262
263         /* Resolve hostname */
264         h = gethostbyname( Host );
265         if( h )
266         {
267                 addr = (struct in_addr *)h->h_addr;
268                 strlcpy( ip, inet_ntoa( *addr ), sizeof( ip ));
269         }
270         else
271         {
272 #ifdef h_errno
273                 Log_Resolver( LOG_WARNING, "Can't resolve \"%s\": %s!", Host, Get_Error( h_errno ));
274 #else
275                 Log_Resolver( LOG_WARNING, "Can't resolve \"%s\"!", Host );
276 #endif
277                 strcpy( ip, "" );
278         }
279         if( ip[0] ) Log_Resolver( LOG_DEBUG, "Ok, translated \"%s\" to %s.", Host, ip );
280
281         /* Write result into pipe to parent */
282         len = strlen( ip );
283         ip[len] = '\n'; len++;
284         if( (size_t)write( w_fd, ip, len ) != (size_t)len )
285         {
286                 Log_Resolver( LOG_CRIT, "Resolver: Can't write to parent: %s!", strerror( errno ));
287                 close( w_fd );
288         }
289 } /* Do_ResolveName */
290
291
292 #ifdef h_errno
293
294 LOCAL CHAR *
295 Get_Error( INT H_Error )
296 {
297         /* Get error message for H_Error */
298
299         switch( H_Error )
300         {
301                 case HOST_NOT_FOUND:
302                         return "host not found";
303                 case NO_DATA:
304                         return "name valid but no IP address defined";
305                 case NO_RECOVERY:
306                         return "name server error";
307                 case TRY_AGAIN:
308                         return "name server temporary not available";
309                 default:
310                         return "unknown error";
311         }
312 } /* Get_Error */
313
314 #endif
315
316
317 /* -eof- */