VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/dnsproxy/dnsproxy.c@ 23462

最後變更 在這個檔案從23462是 23157,由 vboxsync 提交於 16 年 前

NAT: bsd mbuf and dnsproxy conflicts are resolved

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 18.5 KB
 
1/* $Id: dnsproxy.c 23157 2009-09-19 19:17:24Z vboxsync $ */
2/*
3 * Copyright (c) 2003,2004,2005 Armin Wolfermann
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24#ifndef VBOX
25#include <config.h>
26#include <errno.h>
27#include <pwd.h>
28#include <signal.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33#else
34#include "slirp.h"
35#endif
36
37#ifndef VBOX
38#define GLOBALS 1
39#include "dnsproxy.h"
40
41#define RD(x) (*(x + 2) & 0x01)
42#define MAX_BUFSPACE 512
43
44static unsigned short queryid = 0;
45#define QUERYID queryid++
46
47static struct sockaddr_in authoritative_addr;
48static struct sockaddr_in recursive_addr;
49static int sock_query;
50static int sock_answer;
51static int dnsproxy_sig;
52
53extern int event_gotsig;
54extern int (*event_sigcb)(void);
55
56#ifdef DEBUG
57char *malloc_options = "AGZ";
58#endif
59
60/* signal_handler -- Native signal handler. Set external flag for libevent
61 * and store type of signal. Real signal handling is done in signal_event.
62 */
63
64RETSIGTYPE
65signal_handler(int sig)
66{
67 event_gotsig = 1;
68 dnsproxy_sig = sig;
69}
70
71/* signal_event -- Called by libevent to deliver a signal.
72 */
73
74int
75signal_event(void)
76{
77 fatal("exiting on signal %d", dnsproxy_sig);
78 return 0;
79}
80
81#else
82
83# define RD(x) (*(x + 2) & 0x01)
84# define MAX_BUFSPACE 512
85
86# define QUERYID queryid++
87
88#endif
89/* timeout -- Called by the event loop when a query times out. Removes the
90 * query from the queue.
91 */
92/* ARGSUSED */
93#ifndef VBOX
94static void
95timeout(int fd, short event, void *arg)
96{
97 /* here we should check if we reached the end of the DNS server list */
98 hash_remove_request(pData, (struct request *)arg);
99 free((struct request *)arg);
100 ++removed_queries;
101}
102#else
103static void
104timeout(PNATState pData, struct socket *so, void *arg)
105{
106 struct request *req = (struct request *)arg;
107 struct dns_entry *de;
108 de = TAILQ_PREV(req->dns_server, dns_list_head, de_list);
109 /* here we should check if we reached the end of the DNS server list */
110 if (de == NULL)
111 {
112 hash_remove_request(pData, req);
113 RTMemFree(req);
114 ++removed_queries;
115 }
116 else
117 {
118 struct ip *ip;
119 struct udphdr *udp;
120 int iphlen;
121 struct socket *so1 = socreate();
122 struct mbuf *m = NULL;
123 char *data;
124 if (so1 == NULL)
125 {
126 LogRel(("NAT: can't create DNS socket \n"));
127 return;
128 }
129 if(udp_attach(pData, so1, 0) == -1)
130 {
131 LogRel(("NAT: can't attach udp socket\n"));
132 sofree(pData, so1);
133 return;
134 }
135#ifndef VBOX_WITH_SLIRP_BSD_MBUF
136 m = m_get(pData);
137#else
138 m = m_getcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR);
139#endif
140 if (m == NULL)
141 {
142 LogRel(("NAT: Can't allocate mbuf\n"));
143 udp_detach(pData, so1);
144 return;
145 }
146 /* mbuf initialization */
147 m->m_data += if_maxlinkhdr;
148 ip = mtod(m, struct ip *);
149 udp = (struct udphdr *)&ip[1]; /* ip attributes */
150 data = (char *)&udp[1];
151 iphlen = sizeof(struct ip);
152 m->m_len += sizeof(struct ip);
153 m->m_len += sizeof(struct udphdr);
154 m->m_len += req->nbyte;
155 ip->ip_src.s_addr = so->so_laddr.s_addr;
156 ip->ip_dst.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);
157 udp->uh_dport = ntohs(53);
158 udp->uh_sport = so->so_lport;
159 memcpy(data, req->byte, req->nbyte); /* coping initial req */
160
161 so1->so_laddr = so->so_laddr;
162 so1->so_lport = so->so_lport;
163 so1->so_faddr = so->so_faddr;
164 so1->so_fport = so->so_fport;
165 req->dns_server = de;
166 so1->so_timeout_arg = req;
167 so1->so_timeout = timeout;
168 dnsproxy_query(pData, so1, m, iphlen);
169 }
170}
171#endif
172
173/* do_query -- Called by the event loop when a packet arrives at our
174 * listening socket. Read the packet, create a new query, append it to the
175 * queue and send it to the correct server.
176 *
177 * Slirp: this routine should be called from udp_input
178 * socket is Slirp's construction (here we should set expiration time for socket)
179 * mbuf points on ip header to easy fetch information about source and destination.
180 * iphlen - len of ip header
181 */
182
183/* ARGSUSED */
184#ifndef VBOX
185static void
186do_query(int fd, short event, void *arg)
187#else
188void
189dnsproxy_query(PNATState pData, struct socket *so, struct mbuf *m, int iphlen)
190#endif
191{
192#ifndef VBOX
193 char buf[MAX_BUFSPACE];
194 unsigned int fromlen = sizeof(fromaddr);
195 struct timeval tv;
196#else
197 struct ip *ip;
198 char *buf;
199 int retransmit;
200 struct udphdr *udp;
201#endif
202 struct sockaddr_in addr;
203 struct request *req = NULL;
204#ifndef VBOX
205 struct sockaddr_in fromaddr;
206#else
207 struct sockaddr_in fromaddr = { 0, };
208#endif
209 int byte = 0;
210
211 ++all_queries;
212
213#ifndef VBOX
214 /* Reschedule event */
215 event_add((struct event *)arg, NULL);
216
217 /* read packet from socket */
218 if ((byte = recvfrom(fd, buf, sizeof(buf), 0,
219 (struct sockaddr *)&fromaddr, &fromlen)) == -1) {
220 LogRel(("recvfrom failed: %s", strerror(errno)));
221 ++dropped_queries;
222 return;
223 }
224#else
225 ip = mtod(m, struct ip *);
226 udp = (struct udphdr *)(m->m_data + iphlen);
227
228 fromaddr.sin_addr.s_addr = ip->ip_src.s_addr;
229 fromaddr.sin_port = udp->uh_sport;
230 fromaddr.sin_family = AF_INET;
231
232 iphlen += sizeof (struct udphdr);
233 byte = m->m_len - iphlen; /* size of IP header + udp header size */
234 /* the validness of ip and udp header has been already checked so we shouldn't care if */
235 buf = m->m_data + iphlen;
236#endif
237
238 /* check for minimum dns packet length */
239 if (byte < 12) {
240 LogRel(("query too short from %s",
241 inet_ntoa(fromaddr.sin_addr)));
242 ++dropped_queries;
243 return;
244 }
245
246#ifndef VBOX
247 /* allocate new request */
248 if ((req = calloc(1, sizeof(struct request))) == NULL) {
249 LogRel(("calloc: %s", strerror(errno)));
250 ++dropped_queries;
251 return;
252 }
253
254 req->id = QUERYID;
255 memcpy(&req->client, &fromaddr, sizeof(struct sockaddr_in));
256 memcpy(&req->clientid, &buf[0], 2);
257#else
258 /* allocate new request */
259 req = so->so_timeout_arg; /* in slirp we might re-send the query*/
260 if (req == NULL)
261 {
262 if ((req = RTMemAllocZ(sizeof(struct request) + byte)) == NULL) {
263 LogRel(("calloc: %s", strerror(errno)));
264 ++dropped_queries;
265 return;
266 }
267 }
268
269 /* fill the request structure */
270 if (so->so_timeout_arg == NULL)
271 {
272 req->id = QUERYID;
273 memcpy(&req->client, &fromaddr, sizeof(struct sockaddr_in));
274 memcpy(&req->clientid, &buf[0], 2);
275 req->dns_server = TAILQ_LAST(&pData->dns_list_head, dns_list_head);
276 if (req->dns_server == NULL)
277 {
278 static int fail_counter = 0;
279 RTMemFree(req);
280 if (fail_counter == 0)
281 LogRel(("NAT/dnsproxy: Empty DNS entry (suppressed 100 times)\n"));
282 else
283 fail_counter = (fail_counter == 100 ? 0 : fail_counter + 1);
284 return;
285
286 }
287 retransmit = 0;
288 so->so_timeout = timeout;
289 so->so_timeout_arg = req;
290 req->nbyte = byte;
291 memcpy(req->byte, buf, byte); /* copying original request */
292 }
293 else
294 {
295 retransmit = 1;
296 }
297#endif
298
299#ifndef VBOX
300 /* where is this query coming from? */
301 if (is_internal(pData, fromaddr.sin_addr)) {
302 req->recursion = RD(buf);
303 DPRINTF(("Internal query RD=%d\n", req->recursion));
304 } else {
305 /* no recursion for foreigners */
306 req->recursion = 0;
307 DPRINTF(("External query RD=%d\n", RD(buf)));
308 }
309
310 /* insert it into the hash table */
311 hash_add_request(pData, req);
312#else
313 req->recursion = 0;
314 DPRINTF(("External query RD=%d\n", RD(buf)));
315 if (retransmit == 0)
316 hash_add_request(pData, req);
317#endif
318
319 /* overwrite the original query id */
320 memcpy(&buf[0], &req->id, 2);
321
322#ifndef VBOX
323 if (req->recursion) {
324
325 /* recursive queries timeout in 90s */
326 event_set(&req->timeout, -1, 0, timeout, req);
327 tv.tv_sec=recursive_timeout; tv.tv_usec=0;
328 event_add(&req->timeout, &tv);
329
330 /* send it to our recursive server */
331 if ((byte = sendto(sock_answer, buf, (unsigned int)byte, 0,
332 (struct sockaddr *)&recursive_addr,
333 sizeof(struct sockaddr_in))) == -1) {
334 LogRel(("sendto failed: %s", strerror(errno)));
335 ++dropped_queries;
336 return;
337 }
338
339 ++recursive_queries;
340
341 } else {
342
343 /* authoritative queries timeout in 10s */
344 event_set(&req->timeout, -1, 0, timeout, req);
345 tv.tv_sec=authoritative_timeout; tv.tv_usec=0;
346 event_add(&req->timeout, &tv);
347
348 /* send it to our authoritative server */
349 if ((byte = sendto(sock_answer, buf, (unsigned int)byte, 0,
350 (struct sockaddr *)&authoritative_addr,
351 sizeof(struct sockaddr_in))) == -1) {
352 LogRel(("sendto failed: %s", strerror(errno)));
353 ++dropped_queries;
354 return;
355 }
356
357#else
358 so->so_expire = curtime + recursive_timeout * 1000; /* let's slirp to care about expiration */
359 memset(&addr, 0, sizeof(struct sockaddr_in));
360 addr.sin_family = AF_INET;
361 addr.sin_addr.s_addr = req->dns_server->de_addr.s_addr;
362 addr.sin_port = htons(53);
363 so->so_expire = curtime + recursive_timeout * 1000; /* let's slirp to care about expiration */
364 /* send it to our authoritative server */
365 Log2(("NAT: request will be sent to %R[IP4] on %R[natsock]\n", &addr.sin_addr, so));
366 if ((byte = sendto(so->s, buf, (unsigned int)byte, 0,
367 (struct sockaddr *)&addr,
368 sizeof(struct sockaddr_in))) == -1) {
369 LogRel(("sendto failed: %s", strerror(errno)));
370 ++dropped_queries;
371 return;
372 }
373 so->so_state = SS_ISFCONNECTED; /* now it's selected */
374 Log2(("NAT: request was sent to %R[IP4] on %R[natsock]\n", &addr.sin_addr, so));
375#endif
376 ++authoritative_queries;
377#ifndef VBOX
378 }
379#endif
380}
381
382/* do_answer -- Process a packet coming from our authoritative or recursive
383 * server. Find the corresponding query and send answer back to querying
384 * host.
385 *
386 * Slirp: we call this from the routine from socrecvfrom routine handling UDP responses.
387 * So at the moment of call response already has been readed and packed into the mbuf
388 */
389
390/* ARGSUSED */
391#ifndef VBOX
392static void
393do_answer(int fd, short event, void *arg)
394#else
395void
396dnsproxy_answer(PNATState pData, struct socket *so, struct mbuf *m)
397#endif
398{
399#ifndef VBOX
400 char buf[MAX_BUFSPACE];
401 int byte = 0;
402 struct request *query = NULL;
403
404 /* Reschedule event */
405 event_add((struct event *)arg, NULL);
406
407 /* read packet from socket */
408 if ((byte = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL)) == -1) {
409 LogRel(("recvfrom failed: %s", strerror(errno)));
410 ++dropped_answers;
411 return;
412 }
413#else
414 char *buf;
415 int byte;
416 struct request *query = NULL;
417 byte = m->m_len;
418 buf = mtod(m, char *);
419#endif
420
421 /* check for minimum dns packet length */
422 if (byte < 12) {
423 LogRel(("answer too short"));
424 ++dropped_answers;
425 return;
426 }
427
428 /* find corresponding query */
429#ifdef VBOX
430 if ((query = hash_find_request(pData, *((unsigned short *)buf))) == NULL) {
431 ++late_answers;
432 /* Probably, this request wasn't serviced by
433 * dnsproxy so we won't care about it here*/
434 so->so_expire = curtime + SO_EXPIREFAST;
435 Log2(("NAT: query wasn't found\n"));
436 return;
437 }
438 so->so_timeout = NULL;
439 so->so_timeout_arg = NULL;
440#else
441 if ((query = hash_find_request(pData, *((unsigned short *)&buf))) == NULL) {
442 ++late_answers;
443 return;
444 }
445 event_del(&query->timeout);
446#endif
447 hash_remove_request(pData, query);
448
449 /* restore original query id */
450 memcpy(&buf[0], &query->clientid, 2);
451
452#ifndef VBOX
453 /* Slirp: will send mbuf to guest by itself */
454 /* send answer back to querying host */
455 if (sendto(sock_query, buf, (unsigned int)byte, 0,
456 (struct sockaddr *)&query->client,
457 sizeof(struct sockaddr_in)) == -1) {
458 LogRel(("sendto failed: %s", strerror(errno)));
459 ++dropped_answers;
460 } else
461 ++answered_queries;
462
463 free(query);
464#else
465 ++answered_queries;
466
467 RTMemFree(query);
468#endif
469}
470
471/* main -- dnsproxy main function
472 */
473#ifndef VBOX
474int
475main(int argc, char *argv[])
476{
477 int ch;
478 struct passwd *pw = NULL;
479 struct sockaddr_in addr;
480 struct event evq, eva;
481 const char *config = "/etc/dnsproxy.conf";
482 int daemonize = 0;
483
484 /* Process commandline arguments */
485 while ((ch = getopt(argc, argv, "c:dhV")) != -1) {
486 switch (ch) {
487 case 'c':
488 config = optarg;
489 break;
490 case 'd':
491 daemonize = 1;
492 break;
493 case 'V':
494 fprintf(stderr, PACKAGE_STRING "\n");
495 exit(0);
496 /* FALLTHROUGH */
497 case 'h':
498 default:
499 fprintf(stderr,
500 "usage: dnsproxy [-c file] [-dhV]\n" \
501 "\t-c file Read configuration from file\n" \
502 "\t-d Detach and run as a daemon\n" \
503 "\t-h This help text\n" \
504 "\t-V Show version information\n");
505 exit(1);
506 }
507 }
508
509 /* Parse configuration and check required parameters */
510 if (!parse(config))
511 fatal("unable to parse configuration");
512
513 if (!authoritative || !recursive)
514 fatal("No authoritative or recursive server defined");
515
516 if (!listenat)
517 listenat = strdup("0.0.0.0");
518
519 /* Create and bind query socket */
520 if ((sock_query = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
521 fatal("unable to create socket: %s", strerror(errno));
522
523 memset(&addr, 0, sizeof(struct sockaddr_in));
524 addr.sin_addr.s_addr = inet_addr(listenat);
525 addr.sin_port = htons(port);
526 addr.sin_family = AF_INET;
527
528 if (bind(sock_query, (struct sockaddr *)&addr, sizeof(addr)) != 0)
529 fatal("unable to bind socket: %s", strerror(errno));
530
531 /* Create and bind answer socket */
532 if ((sock_answer = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
533 fatal("unable to create socket: %s", strerror(errno));
534
535 memset(&addr, 0, sizeof(struct sockaddr_in));
536 addr.sin_family = AF_INET;
537
538 if (bind(sock_answer, (struct sockaddr *)&addr, sizeof(addr)) != 0)
539 fatal("unable to bind socket: %s", strerror(errno));
540
541 /* Fill sockaddr_in structs for both servers */
542 memset(&authoritative_addr, 0, sizeof(struct sockaddr_in));
543 authoritative_addr.sin_addr.s_addr = inet_addr(authoritative);
544 authoritative_addr.sin_port = htons(authoritative_port);
545 authoritative_addr.sin_family = AF_INET;
546
547 memset(&recursive_addr, 0, sizeof(struct sockaddr_in));
548 recursive_addr.sin_addr.s_addr = inet_addr(recursive);
549 recursive_addr.sin_port = htons(recursive_port);
550 recursive_addr.sin_family = AF_INET;
551
552 /* Daemonize if requested and switch to syslog */
553 if (daemonize) {
554 if (daemon(0, 0) == -1)
555 fatal("unable to daemonize");
556 log_syslog("dnsproxy");
557 }
558
559 /* Find less privileged user */
560 if (user) {
561 pw = getpwnam(user);
562 if (!pw)
563 fatal("unable to find user %s", user);
564 }
565
566 /* Do a chroot if requested */
567 if (chrootdir) {
568 if (chdir(chrootdir) || chroot(chrootdir))
569 fatal("unable to chroot to %s", chrootdir);
570 chdir("/");
571 }
572
573 /* Drop privileges */
574 if (user) {
575 if (setgroups(1, &pw->pw_gid) < 0)
576 fatal("setgroups: %s", strerror(errno));
577#if defined(HAVE_SETRESGID)
578 if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) < 0)
579 fatal("setresgid: %s", strerror(errno));
580#elif defined(HAVE_SETREGID)
581 if (setregid(pw->pw_gid, pw->pw_gid) < 0)
582 fatal("setregid: %s", strerror(errno));
583#else
584 if (setegid(pw->pw_gid) < 0)
585 fatal("setegid: %s", strerror(errno));
586 if (setgid(pw->pw_gid) < 0)
587 fatal("setgid: %s", strerror(errno));
588#endif
589#if defined(HAVE_SETRESUID)
590 if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0)
591 fatal("setresuid: %s", strerror(errno));
592#elif defined(HAVE_SETREUID)
593 if (setreuid(pw->pw_uid, pw->pw_uid) < 0)
594 fatal("setreuid: %s", strerror(errno));
595#else
596 if (seteuid(pw->pw_uid) < 0)
597 fatal("seteuid: %s", strerror(errno));
598 if (setuid(pw->pw_uid) < 0)
599 fatal("setuid: %s", strerror(errno));
600#endif
601 }
602
603 /* Init event handling */
604 event_init();
605
606 event_set(&evq, sock_query, EV_READ, do_query, &evq);
607 event_add(&evq, NULL);
608
609 event_set(&eva, sock_answer, EV_READ, do_answer, &eva);
610 event_add(&eva, NULL);
611
612 /* Zero counters and start statistics timer */
613 statistics_start();
614
615 /* Take care of signals */
616 if (signal(SIGINT, signal_handler) == SIG_ERR)
617 fatal("unable to mask signal SIGINT: %s", strerror(errno));
618
619 if (signal(SIGTERM, signal_handler) == SIG_ERR)
620 fatal("unable to mask signal SIGTERM: %s", strerror(errno));
621
622 if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
623 fatal("unable to mask signal SIGHUP: %s", strerror(errno));
624
625 event_sigcb = signal_event;
626
627 /* Start libevent main loop */
628 event_dispatch();
629
630 return 0;
631
632}
633#else
634int
635dnsproxy_init(PNATState pData)
636{
637 /* globals initialization */
638 authoritative_port = 53;
639 authoritative_timeout = 10;
640 recursive_port = 53;
641 recursive_timeout = 2;
642 stats_timeout = 3600;
643 dns_port = 53;
644 return 0;
645}
646#endif
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette