Annotation of embedaddon/mtr/ui/dns.c, revision 1.1.1.1
1.1 misho 1: /*
2: mtr -- a network diagnostic tool
3: Copyright (C) 1997,1998 Matt Kimball
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 version 2 as
7: published by the Free Software Foundation.
8:
9: This program is distributed in the hope that it will be useful,
10: but WITHOUT ANY WARRANTY; without even the implied warranty of
11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: GNU General Public License for more details.
13:
14: You should have received a copy of the GNU General Public License
15: along with this program; if not, write to the Free Software
16: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17: */
18:
19: /*
20: Non-blocking DNS portion --
21: Copyright (C) 1998 by Simon Kirby <sim@neato.org>
22: Released under GPL, as above.
23: */
24:
25: #include "config.h"
26:
27: #ifdef HAVE_ERROR_H
28: #include <error.h>
29: #else
30: #include "portability/error.h"
31: #endif
32: #include <errno.h>
33: #include <unistd.h>
34: #include <fcntl.h>
35: #include <string.h>
36: #include <stdio.h>
37: #include <stdlib.h>
38: #include <signal.h>
39:
40: #include "mtr.h"
41: #include "dns.h"
42: #include "net.h"
43: #include "utils.h"
44:
45: struct dns_results {
46: ip_t ip;
47: char *name;
48: struct dns_results *next;
49: };
50:
51: static struct dns_results *results;
52:
53: char *strlongip(
54: struct mtr_ctl *ctl,
55: ip_t * ip)
56: {
57: #ifdef ENABLE_IPV6
58: static char addrstr[INET6_ADDRSTRLEN];
59:
60: return (char *) inet_ntop(ctl->af, ip, addrstr, sizeof addrstr);
61: #else
62: return inet_ntoa(*ip);
63: #endif
64: }
65:
66:
67: #ifdef ENABLE_IPV6
68: #define UNUSED_IF_NO_IPV6 /* empty */
69: #else
70: #define UNUSED_IF_NO_IPV6 ATTRIBUTE_UNUSED
71: #endif
72:
73: static int todns[2], fromdns[2];
74: static FILE *fromdnsfp;
75:
76: static int longipstr(
77: char *s,
78: ip_t * dst,
79: int family UNUSED_IF_NO_IPV6)
80: {
81: #ifdef ENABLE_IPV6
82: return inet_pton(family, s, dst);
83: #else
84: return inet_aton(s, dst);
85: #endif
86: }
87:
88:
89: struct hostent *dns_forward(
90: const char *name)
91: {
92: struct hostent *host;
93:
94: if ((host = gethostbyname(name)))
95: return host;
96: else
97: return NULL;
98: }
99:
100:
101: static struct dns_results *findip(
102: struct mtr_ctl *ctl,
103: ip_t * ip)
104: {
105: struct dns_results *t;
106:
107: for (t = results; t; t = t->next) {
108: if (addrcmp((void *) ip, (void *) &t->ip, ctl->af) == 0)
109: return t;
110: }
111:
112: return NULL;
113: }
114:
115: static void set_sockaddr_ip(
116: struct mtr_ctl *ctl,
117: struct sockaddr_storage *sa,
118: ip_t * ip)
119: {
120: struct sockaddr_in *sa_in;
121: struct sockaddr_in6 *sa_in6;
122:
123: memset(sa, 0, sizeof(struct sockaddr_storage));
124: switch (ctl->af) {
125: case AF_INET:
126: sa_in = (struct sockaddr_in *) sa;
127: sa_in->sin_family = ctl->af;
128: addrcpy((void *) &sa_in->sin_addr, (void *) ip, ctl->af);
129: break;
130: case AF_INET6:
131: sa_in6 = (struct sockaddr_in6 *) sa;
132: sa_in6->sin6_family = ctl->af;
133: addrcpy((void *) &sa_in6->sin6_addr, (void *) ip, ctl->af);
134: break;
135: }
136: }
137:
138: void dns_open(
139: struct mtr_ctl *ctl)
140: {
141: int pid;
142:
143: if (pipe(todns) < 0) {
144: error(EXIT_FAILURE, errno, "can't make a pipe for DNS process");
145: }
146:
147: if (pipe(fromdns) < 0) {
148: error(EXIT_FAILURE, errno, "can't make a pipe for DNS process");
149: }
150: fflush(stdout);
151: pid = fork();
152: if (pid < 0) {
153: error(EXIT_FAILURE, errno, "can't fork for DNS process");
154: }
155: if (pid == 0) {
156: char buf[2048];
157: int i;
158: FILE *infp;
159:
160: /* Automatically reap children. */
161: if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) {
162: error(EXIT_FAILURE, errno, "signal");
163: }
164:
165: /* Close all unneccessary FDs.
166: for debugging and error reporting, keep std-in/out/err. */
167: for (i = 3; i < fromdns[1]; i++) {
168: if (i == todns[0])
169: continue;
170: if (i == fromdns[1])
171: continue;
172: close(i);
173: }
174: infp = fdopen(todns[0], "r");
175:
176: while (fgets(buf, sizeof(buf), infp)) {
177: ip_t host;
178: struct sockaddr_storage sa;
179: socklen_t salen;
180: char hostname[NI_MAXHOST];
181: char result[INET6_ADDRSTRLEN + NI_MAXHOST + 2];
182:
183: if (!fork()) {
184: int rv;
185:
186: buf[strlen(buf) - 1] = 0; /* chomp newline. */
187:
188: longipstr(buf, &host, ctl->af);
189: set_sockaddr_ip(ctl, &sa, &host);
190: salen = (ctl->af == AF_INET) ? sizeof(struct sockaddr_in) :
191: sizeof(struct sockaddr_in6);
192:
193: rv = getnameinfo((struct sockaddr *) &sa, salen,
194: hostname, sizeof(hostname), NULL, 0, 0);
195: if (rv == 0) {
196: snprintf(result, sizeof(result),
197: "%s %s\n", strlongip(ctl, &host), hostname);
198:
199: rv = write(fromdns[1], result, strlen(result));
200: if (rv < 0)
201: error(0, errno, "write DNS lookup result");
202: }
203:
204: exit(EXIT_SUCCESS);
205: }
206: }
207: exit(EXIT_SUCCESS);
208: } else {
209: int flags;
210:
211: /* the parent. */
212: close(todns[0]); /* close the pipe ends we don't need. */
213: close(fromdns[1]);
214: fromdnsfp = fdopen(fromdns[0], "r");
215: flags = fcntl(fromdns[0], F_GETFL, 0);
216: flags |= O_NONBLOCK;
217: fcntl(fromdns[0], F_SETFL, flags);
218: }
219: }
220:
221: int dns_waitfd(
222: void)
223: {
224: return fromdns[0];
225: }
226:
227:
228: void dns_ack(
229: struct mtr_ctl *ctl)
230: {
231: char buf[2048], host[NI_MAXHOST], name[NI_MAXHOST];
232: ip_t hostip;
233: struct dns_results *r;
234:
235: while (fgets(buf, sizeof(buf), fromdnsfp)) {
236: sscanf(buf, "%s %s", host, name);
237:
238: longipstr(host, &hostip, ctl->af);
239: r = findip(ctl, &hostip);
240: if (r)
241: r->name = xstrdup(name);
242: else
243: error(0, 0, "dns_ack: Couldn't find host %s", host);
244: }
245: }
246:
247:
248:
249: #ifdef ENABLE_IPV6
250:
251: int dns_waitfd6(
252: void)
253: {
254: return -1;
255: }
256:
257: void dns_ack6(
258: void)
259: {
260: return;
261: }
262:
263: #endif
264:
265:
266: char *dns_lookup2(
267: struct mtr_ctl *ctl,
268: ip_t * ip)
269: {
270: struct dns_results *r;
271: char buf[INET6_ADDRSTRLEN + 1];
272: int rv;
273:
274: r = findip(ctl, ip);
275: if (r) {
276: /* we've got a result. */
277: if (r->name)
278: return r->name;
279: else
280: return strlongip(ctl, ip);
281: } else {
282: r = xmalloc(sizeof(struct dns_results));
283: memcpy(&r->ip, ip, sizeof(r->ip));
284: r->name = NULL;
285: r->next = results;
286: results = r;
287: snprintf(buf, sizeof(buf), "%s\n", strlongip(ctl, ip));
288: rv = write(todns[1], buf, strlen(buf));
289: if (rv < 0)
290: error(0, errno, "couldn't write to resolver process");
291: }
292: return strlongip(ctl, ip);
293: }
294:
295:
296: char *dns_lookup(
297: struct mtr_ctl *ctl,
298: ip_t * ip)
299: {
300: char *t;
301:
302: if (!ctl->dns || !ctl->use_dns)
303: return NULL;
304: t = dns_lookup2(ctl, ip);
305: return t;
306: }
307:
308: /* XXX check if necessary/exported. */
309:
310: /* Resolve an IP address to a hostname. */
311: struct hostent *addr2host(
312: const char *addr,
313: int family)
314: {
315: int len = 0;
316: switch (family) {
317: case AF_INET:
318: len = sizeof(struct in_addr);
319: break;
320: #ifdef ENABLE_IPV6
321: case AF_INET6:
322: len = sizeof(struct in6_addr);
323: break;
324: #endif
325: }
326: return gethostbyaddr(addr, len, family);
327: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>