Annotation of ircnowd/src/ngircd/resolve.c, Revision 1.1.1.1
1.1 tomglok 1: /*
2: * ngIRCd -- The Next Generation IRC Daemon
3: * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
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:
12: #define RESOLVER_TIMEOUT (Conf_PongTimeout*3)/4
13:
14: #include "portab.h"
15:
16: /**
17: * @file
18: * Asynchronous resolver
19: */
20:
21: #include <assert.h>
22: #include <errno.h>
23: #include <stdlib.h>
24: #include <string.h>
25: #include <unistd.h>
26: #include <sys/stat.h>
27: #include <sys/types.h>
28: #include <sys/socket.h>
29: #include <netinet/in.h>
30: #include <netdb.h>
31:
32: #ifdef IDENTAUTH
33: #ifdef HAVE_IDENT_H
34: #include <ident.h>
35: #endif
36: #endif
37:
38: #include "conn.h"
39: #include "conf.h"
40: #include "log.h"
41: #include "ng_ipaddr.h"
42:
43: #include "resolve.h"
44:
45: static void Do_ResolveAddr PARAMS(( const ng_ipaddr_t *Addr, int Sock, int w_fd ));
46: static void Do_ResolveName PARAMS(( const char *Host, int w_fd ));
47:
48: #ifdef WANT_IPV6
49: extern bool Conf_ConnectIPv4;
50: extern bool Conf_ConnectIPv6;
51: #endif
52:
53:
54: /**
55: * Resolve IP (asynchronous!).
56: */
57: GLOBAL bool
58: Resolve_Addr(PROC_STAT * s, const ng_ipaddr_t *Addr, int identsock,
59: void (*cbfunc) (int, short))
60: {
61: int pipefd[2];
62: pid_t pid;
63:
64: assert(s != NULL);
65:
66: pid = Proc_Fork(s, pipefd, cbfunc, RESOLVER_TIMEOUT);
67: if (pid > 0) {
68: LogDebug("Resolver for %s created (PID %d).", ng_ipaddr_tostr(Addr), pid);
69: return true;
70: } else if( pid == 0 ) {
71: /* Sub process */
72: Log_Init_Subprocess("Resolver");
73: Conn_CloseAllSockets(identsock);
74: Do_ResolveAddr(Addr, identsock, pipefd[1]);
75: Log_Exit_Subprocess("Resolver");
76: exit(0);
77: }
78: return false;
79: } /* Resolve_Addr */
80:
81:
82: /**
83: * Resolve hostname (asynchronous!).
84: */
85: GLOBAL bool
86: Resolve_Name( PROC_STAT *s, const char *Host, void (*cbfunc)(int, short))
87: {
88: int pipefd[2];
89: pid_t pid;
90:
91: assert(s != NULL);
92:
93: pid = Proc_Fork(s, pipefd, cbfunc, RESOLVER_TIMEOUT);
94: if (pid > 0) {
95: /* Main process */
96: #ifdef DEBUG
97: Log( LOG_DEBUG, "Resolver for \"%s\" created (PID %d).", Host, pid );
98: #endif
99: return true;
100: } else if( pid == 0 ) {
101: /* Sub process */
102: Log_Init_Subprocess("Resolver");
103: Conn_CloseAllSockets(NONE);
104: Do_ResolveName(Host, pipefd[1]);
105: Log_Exit_Subprocess("Resolver");
106: exit(0);
107: }
108: return false;
109: } /* Resolve_Name */
110:
111: #if !defined(HAVE_WORKING_GETADDRINFO) || !defined(HAVE_GETNAMEINFO)
112: #ifdef h_errno
113: static char *
114: Get_Error( int H_Error )
115: {
116: /* Get error message for H_Error */
117: switch( H_Error ) {
118: case HOST_NOT_FOUND:
119: return "host not found";
120: case NO_DATA:
121: return "name valid but no IP address defined";
122: case NO_RECOVERY:
123: return "name server error";
124: case TRY_AGAIN:
125: return "name server temporary not available";
126: }
127: return "unknown error";
128: }
129: #endif
130: #endif
131:
132:
133: /* Do "IDENT" (aka "AUTH") lookup and append result to resolved_addr array */
134: static void
135: Do_IdentQuery(int identsock, array *resolved_addr)
136: {
137: #ifdef IDENTAUTH
138: char *res;
139:
140: if (identsock < 0)
141: return;
142:
143: #ifdef DEBUG
144: Log_Subprocess(LOG_DEBUG, "Doing IDENT lookup on socket %d ...",
145: identsock);
146: #endif
147: res = ident_id( identsock, 10 );
148: #ifdef DEBUG
149: Log_Subprocess(LOG_DEBUG, "Ok, IDENT lookup on socket %d done: \"%s\"",
150: identsock, res ? res : "(NULL)");
151: #endif
152: if (!res) /* no result */
153: return;
154: if (!array_cats(resolved_addr, res))
155: Log_Subprocess(LOG_WARNING,
156: "Resolver: Cannot copy IDENT result: %s!",
157: strerror(errno));
158:
159: free(res);
160: #else
161: (void) identsock;
162: (void) resolved_addr;
163: #endif
164: }
165:
166:
167: /**
168: * perform reverse DNS lookup and put result string into resbuf.
169: * If no hostname could be obtained, this function stores the string representation of
170: * the IP address in resbuf and returns false.
171: * @param IpAddr ip address to resolve
172: * @param resbuf result buffer to store DNS name/string representation of ip address
173: * @param reslen size of result buffer (must be >= NGT_INET_ADDRSTRLEN)
174: * @return true if reverse lookup successful, false otherwise
175: */
176: static bool
177: ReverseLookup(const ng_ipaddr_t *IpAddr, char *resbuf, size_t reslen)
178: {
179: char tmp_ip_str[NG_INET_ADDRSTRLEN];
180: const char *errmsg;
181: #ifdef HAVE_GETNAMEINFO
182: static const char funcname[]="getnameinfo";
183: int res;
184:
185: *resbuf = 0;
186:
187: res = getnameinfo((struct sockaddr *) IpAddr, ng_ipaddr_salen(IpAddr),
188: resbuf, (socklen_t)reslen, NULL, 0, NI_NAMEREQD);
189: if (res == 0)
190: return true;
191:
192: if (res == EAI_SYSTEM)
193: errmsg = strerror(errno);
194: else
195: errmsg = gai_strerror(res);
196: #else
197: const struct sockaddr_in *Addr = (const struct sockaddr_in *) IpAddr;
198: struct hostent *h;
199: static const char funcname[]="gethostbyaddr";
200:
201: h = gethostbyaddr((char *)&Addr->sin_addr, sizeof(Addr->sin_addr), AF_INET);
202: if (h) {
203: if (strlcpy(resbuf, h->h_name, reslen) < reslen)
204: return true;
205: errmsg = "hostname too long";
206: } else {
207: # ifdef h_errno
208: errmsg = Get_Error(h_errno);
209: # else
210: errmsg = "unknown error";
211: # endif /* h_errno */
212: }
213: #endif /* HAVE_GETNAMEINFO */
214:
215: assert(errmsg);
216: assert(reslen >= NG_INET_ADDRSTRLEN);
217: ng_ipaddr_tostr_r(IpAddr, tmp_ip_str);
218:
219: Log_Subprocess(LOG_WARNING, "Can't resolve address \"%s\": %s [%s].",
220: tmp_ip_str, errmsg, funcname);
221: strlcpy(resbuf, tmp_ip_str, reslen);
222: return false;
223: }
224:
225:
226: /**
227: * perform DNS lookup of given host name and fill IpAddr with a list of
228: * ip addresses associated with that name.
229: * ip addresses found are stored in the "array *IpAddr" argument (type ng_ipaddr_t)
230: * @param hostname The domain name to look up.
231: * @param IpAddr pointer to empty and initialized array to store results
232: * @return true if lookup successful, false if domain name not found
233: */
234: static bool
235: #ifdef HAVE_WORKING_GETADDRINFO
236: ForwardLookup(const char *hostname, array *IpAddr, int af)
237: #else
238: ForwardLookup(const char *hostname, array *IpAddr, UNUSED int af)
239: #endif
240: {
241: ng_ipaddr_t addr;
242:
243: #ifdef HAVE_WORKING_GETADDRINFO
244: int res;
245: struct addrinfo *a, *ai_results;
246: static struct addrinfo hints;
247:
248: hints.ai_socktype = SOCK_STREAM;
249: hints.ai_protocol = IPPROTO_TCP;
250: hints.ai_family = af;
251:
252: memset(&addr, 0, sizeof(addr));
253:
254: res = getaddrinfo(hostname, NULL, &hints, &ai_results);
255: switch (res) {
256: case 0: break;
257: case EAI_SYSTEM:
258: Log_Subprocess(LOG_WARNING, "Can't resolve \"%s\": %s", hostname, strerror(errno));
259: return false;
260: default:
261: Log_Subprocess(LOG_WARNING, "Can't resolve \"%s\": %s", hostname, gai_strerror(res));
262: return false;
263: }
264:
265: for (a = ai_results; a != NULL; a = a->ai_next) {
266: assert((size_t)a->ai_addrlen <= sizeof(addr));
267:
268: if ((size_t)a->ai_addrlen > sizeof(addr))
269: continue;
270:
271: memcpy(&addr, a->ai_addr, a->ai_addrlen);
272:
273: if (!array_catb(IpAddr, (char *)&addr, sizeof(addr)))
274: break;
275: }
276:
277: freeaddrinfo(ai_results);
278: return a == NULL;
279: #else
280: struct hostent *h = gethostbyname(hostname);
281:
282: if (!h) {
283: #ifdef h_errno
284: Log_Subprocess(LOG_WARNING, "Can't resolve \"%s\": %s",
285: hostname, Get_Error(h_errno));
286: #else
287: Log_Subprocess(LOG_WARNING, "Can't resolve \"%s\"", hostname);
288: #endif
289: return false;
290: }
291: memset(&addr, 0, sizeof(addr));
292:
293: addr.sin4.sin_family = AF_INET;
294: memcpy(&addr.sin4.sin_addr, h->h_addr, sizeof(struct in_addr));
295:
296: return array_copyb(IpAddr, (char *)&addr, sizeof(addr));
297: #endif /* HAVE_GETADDRINFO */
298: }
299:
300:
301: static bool
302: Addr_in_list(const array *resolved_addr, const ng_ipaddr_t *Addr)
303: {
304: char tmp_ip_str[NG_INET_ADDRSTRLEN];
305: const ng_ipaddr_t *tmpAddrs = array_start(resolved_addr);
306: size_t len = array_length(resolved_addr, sizeof(*tmpAddrs));
307:
308: assert(len > 0);
309: assert(tmpAddrs);
310:
311: while (len > 0) {
312: if (ng_ipaddr_ipequal(Addr, tmpAddrs))
313: return true;
314: tmpAddrs++;
315: len--;
316: }
317: /* failed; print list of addresses */
318: ng_ipaddr_tostr_r(Addr, tmp_ip_str);
319: len = array_length(resolved_addr, sizeof(*tmpAddrs));
320: tmpAddrs = array_start(resolved_addr);
321:
322: while (len > 0) {
323: Log_Subprocess(LOG_WARNING, "Address mismatch: %s != %s",
324: tmp_ip_str, ng_ipaddr_tostr(tmpAddrs));
325: tmpAddrs++;
326: len--;
327: }
328:
329: return false;
330: }
331:
332:
333: static void
334: Log_Forgery_NoIP(const char *ip, const char *host)
335: {
336: Log_Subprocess(LOG_WARNING,
337: "Possible forgery: %s resolved to \"%s\", which has no IP address!",
338: ip, host);
339: }
340:
341: static void
342: Log_Forgery_WrongIP(const char *ip, const char *host)
343: {
344: Log_Subprocess(LOG_WARNING,
345: "Possible forgery: %s resolved to \"%s\", which points to a different address!",
346: ip, host);
347: }
348:
349:
350: static void
351: ArrayWrite(int fd, const array *a)
352: {
353: size_t len = array_bytes(a);
354: const char *data = array_start(a);
355:
356: assert(data);
357:
358: if( (size_t)write(fd, data, len) != len )
359: Log_Subprocess( LOG_CRIT, "Resolver: Can't write to parent: %s!",
360: strerror(errno));
361: }
362:
363:
364: static void
365: Do_ResolveAddr(const ng_ipaddr_t *Addr, int identsock, int w_fd)
366: {
367: /* Resolver sub-process: resolve IP address and write result into
368: * pipe to parent. */
369: char hostname[CLIENT_HOST_LEN];
370: char tmp_ip_str[NG_INET_ADDRSTRLEN];
371: size_t len;
372: array resolved_addr;
373:
374: array_init(&resolved_addr);
375: ng_ipaddr_tostr_r(Addr, tmp_ip_str);
376: #ifdef DEBUG
377: Log_Subprocess(LOG_DEBUG, "Now resolving %s ...", tmp_ip_str);
378: #endif
379: if (!ReverseLookup(Addr, hostname, sizeof(hostname)))
380: goto dns_done;
381:
382: if (ForwardLookup(hostname, &resolved_addr, ng_ipaddr_af(Addr))) {
383: if (!Addr_in_list(&resolved_addr, Addr)) {
384: Log_Forgery_WrongIP(tmp_ip_str, hostname);
385: strlcpy(hostname, tmp_ip_str, sizeof(hostname));
386: }
387: } else {
388: Log_Forgery_NoIP(tmp_ip_str, hostname);
389: strlcpy(hostname, tmp_ip_str, sizeof(hostname));
390: }
391: #ifdef DEBUG
392: Log_Subprocess(LOG_DEBUG, "Ok, translated %s to \"%s\".", tmp_ip_str, hostname);
393: #endif
394: dns_done:
395: len = strlen(hostname);
396: hostname[len] = '\n';
397: if (!array_copyb(&resolved_addr, hostname, ++len)) {
398: Log_Subprocess(LOG_CRIT,
399: "Resolver: Can't copy resolved name: %s!",
400: strerror(errno));
401: array_free(&resolved_addr);
402: return;
403: }
404:
405: Do_IdentQuery(identsock, &resolved_addr);
406:
407: ArrayWrite(w_fd, &resolved_addr);
408:
409: array_free(&resolved_addr);
410: } /* Do_ResolveAddr */
411:
412:
413: static void
414: Do_ResolveName( const char *Host, int w_fd )
415: {
416: /* Resolver sub-process: resolve name and write result into pipe
417: * to parent. */
418: array IpAddrs;
419: int af;
420: #ifdef DEBUG
421: ng_ipaddr_t *addr;
422: size_t len;
423: #endif
424: Log_Subprocess(LOG_DEBUG, "Now resolving \"%s\" ...", Host);
425:
426: array_init(&IpAddrs);
427:
428: #ifdef WANT_IPV6
429: af = AF_UNSPEC;
430: assert(Conf_ConnectIPv6 || Conf_ConnectIPv4);
431:
432: if (!Conf_ConnectIPv6)
433: af = AF_INET;
434: if (!Conf_ConnectIPv4)
435: af = AF_INET6;
436: #else
437: af = AF_INET;
438: #endif
439: if (!ForwardLookup(Host, &IpAddrs, af)) {
440: close(w_fd);
441: return;
442: }
443: #ifdef DEBUG
444: len = array_length(&IpAddrs, sizeof(*addr));
445: assert(len > 0);
446: addr = array_start(&IpAddrs);
447: assert(addr);
448: for (; len > 0; --len,addr++) {
449: Log_Subprocess(LOG_DEBUG, "translated \"%s\" to %s.",
450: Host, ng_ipaddr_tostr(addr));
451: }
452: #endif
453: /* Write result into pipe to parent */
454: ArrayWrite(w_fd, &IpAddrs);
455:
456: array_free(&IpAddrs);
457: } /* Do_ResolveName */
458:
459:
460: /* -eof- */
CVSweb