VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/hostres.c@ 59157

Last change on this file since 59157 was 59157, checked in by vboxsync, 9 years ago

NAT: G/c unused local variables.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.0 KB
Line 
1/* $Id: hostres.c 59157 2015-12-16 15:41:44Z vboxsync $ */
2/** @file
3 * Host resolver
4 */
5
6/*
7 * Copyright (C) 2009-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef RT_OS_WINDOWS
19# include <netdb.h>
20#endif
21#include <iprt/ctype.h>
22#include <iprt/assert.h>
23#include <slirp.h>
24
25#define isdigit(ch) RT_C_IS_DIGIT(ch)
26#define isalpha(ch) RT_C_IS_ALPHA(ch)
27
28#define DNS_CONTROL_PORT_NUMBER 53
29/* see RFC 1035(4.1.1) */
30struct dnsmsg_header
31{
32 uint16_t id;
33
34 /* XXX: endianness */
35 uint16_t rd:1;
36 uint16_t tc:1;
37 uint16_t aa:1;
38 uint16_t opcode:4;
39 uint16_t qr:1;
40 uint16_t rcode:4;
41 uint16_t Z:3;
42 uint16_t ra:1;
43
44 uint16_t qdcount;
45 uint16_t ancount;
46 uint16_t nscount;
47 uint16_t arcount;
48};
49AssertCompileSize(struct dnsmsg_header, 12);
50
51#define QR_Query 0
52#define QR_Response 1
53
54#define OpCode_Query 0
55
56#define RCode_NoError 0
57#define RCode_FormErr 1
58#define RCode_ServFail 2
59#define RCode_NXDomain 3
60#define RCode_NotImp 4
61#define RCode_Refused 5
62
63#define Type_A 1
64#define Type_CNAME 5
65#define Type_PTR 12
66#define Type_ANY 255
67
68#define Class_IN 1
69#define Class_ANY 255
70
71/* compressed label encoding */
72#define DNS_LABEL_PTR 0xc0
73
74#define DNS_MAX_UDP_LEN 512
75#define DNS_MAX_LABEL_LEN 63
76#define DNS_MAX_NAME_LEN 255
77
78
79/*
80 * A tree of labels.
81 *
82 * rfc1035#section-3.1
83 * rfc1035#section-4.1.4
84 */
85struct label
86{
87 const uint8_t *buf;
88 ssize_t off;
89 struct label *children;
90 struct label *sibling;
91};
92
93
94/*
95 * A structure to build DNS response.
96 */
97struct response
98{
99 struct label *labels; /* already encoded in buf */
100 size_t qlen; /* original question */
101 size_t end; /* of data in buf */
102
103 /* continuous buffer to build the response */
104 uint8_t buf[DNS_MAX_UDP_LEN];
105};
106
107
108static int verify_header(PNATState pData, struct mbuf **pMBuf);
109static struct mbuf *respond(PNATState pData, struct mbuf *m, struct response *res);
110struct mbuf *resolve(PNATState pData, struct mbuf *m, struct response *res, size_t qname, uint16_t qtype);
111struct mbuf *refuse(PNATState pData, struct mbuf *m, unsigned int rcode);
112static ssize_t append_a(struct response *res, const char *name, struct in_addr addr);
113static ssize_t append_cname(struct response *res, const char *name, const char *cname);
114static ssize_t append_rrhdr(struct response *res, const char *name, uint16_t type, uint32_t ttl);
115static ssize_t append_name(struct response *res, const char *name);
116static ssize_t append_u32(struct response *res, uint32_t value);
117static ssize_t append_u16(struct response *res, uint16_t value);
118static ssize_t append_u8(struct response *res, uint8_t value);
119static ssize_t append_bytes(struct response *res, uint8_t *p, size_t size);
120static ssize_t check_space(struct response *res, size_t size);
121
122static void strnlabels(char *namebuf, size_t nbuflen, const uint8_t *msg, size_t off);
123
124static void LogLabelsTree(const char *before, struct label *l, const char *after);
125static void free_labels(struct label *root);
126
127#ifdef VBOX_WITH_DNSMAPPING_IN_HOSTRESOLVER
128static void alterHostentWithDataFromDNSMap(PNATState pData, struct hostent *pHostent);
129#endif
130
131#if 1 /* XXX */
132# define LogErr(args) Log2(args)
133# define LogDbg(args) Log3(args)
134#else
135# define LogErr(args) LogRel(args)
136# define LogDbg(args) LogRel(args)
137#endif
138
139
140struct mbuf *
141hostresolver(PNATState pData, struct mbuf *m)
142{
143 int error;
144
145 struct response res;
146
147 error = verify_header(pData, &m);
148 if (error != 0)
149 return m;
150
151 RT_ZERO(res);
152
153 /*
154 * Do the real work
155 */
156 m = respond(pData, m, &res);
157
158 free_labels(res.labels);
159 return m;
160}
161
162
163struct mbuf *
164refuse(PNATState pData, struct mbuf *m, unsigned int rcode)
165{
166 struct dnsmsg_header *pHdr;
167
168 pHdr = mtod(m, struct dnsmsg_header *);
169 pHdr->qr = QR_Response;
170 pHdr->rcode = rcode;
171 pHdr->ra = 1;
172 pHdr->aa = 0;
173
174 return m;
175}
176
177
178static int
179verify_header(PNATState pData, struct mbuf **pMBuf)
180{
181 struct mbuf *m;
182 struct dnsmsg_header *pHdr;
183 size_t mlen;
184
185 m = *pMBuf;
186
187 /*
188 * In theory we should have called
189 *
190 * m = m_pullup(m, sizeof(struct dnsmsg_header));
191 *
192 * here first (which should have been a nop), but the way mbufs
193 * are used in NAT will always cause a copy that will have no
194 * leading space. We can use m_copyup() instead, but if we are
195 * peeking under the hood anyway, we might as well just rely on
196 * the fact that this header will be contiguous.
197 */
198 pHdr = mtod(m, struct dnsmsg_header *);
199
200 if (RT_UNLIKELY(pHdr->qr != QR_Query))
201 {
202 LogErr(("NAT: hostres: unexpected response\n"));
203 goto drop;
204 }
205
206 mlen = m_length(m, NULL);
207 if (RT_UNLIKELY(mlen > DNS_MAX_UDP_LEN))
208 {
209 LogErr(("NAT: hostres: packet too large\n"));
210 refuse(pData, m, RCode_FormErr); /* or drop? */
211 return 1;
212 }
213
214 if (RT_UNLIKELY(pHdr->opcode != OpCode_Query))
215 {
216 LogErr(("NAT: hostres: unsupported opcode\n"));
217 refuse(pData, m, RCode_NotImp);
218 return 1;
219 }
220
221 if (RT_UNLIKELY(pHdr->Z != 0))
222 {
223 LogErr(("NAT: hostres: MBZ bits are not\n"));
224 refuse(pData, m, RCode_FormErr);
225 return 1;
226 }
227
228 if (RT_UNLIKELY(pHdr->qdcount != RT_H2N_U16_C(1)))
229 {
230 LogErr(("NAT: hostres: multiple questions\n"));
231 refuse(pData, m, RCode_NotImp);
232 return 1;
233 }
234
235 if (RT_UNLIKELY(pHdr->ancount != 0))
236 {
237 LogErr(("NAT: hostres: answers in query\n"));
238 refuse(pData, m, RCode_FormErr);
239 return 1;
240 }
241
242 if (RT_UNLIKELY(pHdr->nscount != 0))
243 {
244 LogErr(("NAT: hostres: authority RRs in query\n"));
245 refuse(pData, m, RCode_FormErr);
246 return 1;
247 }
248
249 if (RT_UNLIKELY(pHdr->arcount != 0))
250 {
251 LogErr(("NAT: hostres: additional info RRs in query\n"));
252 refuse(pData, m, RCode_FormErr);
253 return 1;
254 }
255
256 if (RT_UNLIKELY(mlen < sizeof(*pHdr)
257 + /* qname */ 1
258 + /* qtype */ 2
259 + /* qclass */ 2))
260 {
261 LogErr(("NAT: hostres: packet too small\n"));
262 refuse(pData, m, RCode_FormErr);
263 return 1;
264 }
265
266 return 0;
267
268 drop:
269 if (m != NULL)
270 m_freem(pData, m);
271 *pMBuf = NULL;
272 return 1;
273}
274
275
276static struct mbuf *
277respond(PNATState pData, struct mbuf *m, struct response *res)
278{
279 struct dnsmsg_header *pHdr;
280 size_t mlen;
281 size_t off;
282 size_t qname;
283 uint16_t qtype, qclass;
284 struct label *l;
285
286 /**
287 * Copy the request into the contiguous buffer for the response
288 * and parse the question.
289 */
290
291 mlen = m_length(m, NULL);
292 m_copydata(m, 0, mlen, (char *)res->buf);
293 res->end = res->qlen = mlen;
294
295 /* convert header to response */
296 pHdr = (struct dnsmsg_header *)res->buf;
297 pHdr->qr = QR_Response;
298 pHdr->rcode = RCode_NoError;
299 pHdr->ra = 1; /* the host provides recursion */
300 pHdr->aa = 0; /* we are not authoritative */
301
302 off = sizeof(*pHdr);
303 qname = off;
304
305 /*
306 * Parse/verify QNAME and collect the suffixes to be used for
307 * compression in the answer.
308 */
309 while (off < mlen) {
310 size_t loff, llen;
311 uint8_t c;
312
313 c = res->buf[off];
314
315 /*
316 * There's just one question with just one name, so there are
317 * no other labels it can point to. Thus all well-formed
318 * names with a pointer can only be infinite loops.
319 */
320 if ((c & DNS_LABEL_PTR) == DNS_LABEL_PTR)
321 {
322 LogErr(("NAT: hostres: label pointer in the qname\n"));
323 return refuse(pData, m, RCode_FormErr);
324 }
325
326 if ((c & DNS_LABEL_PTR) != 0)
327 {
328 LogErr(("NAT: hostres: unexpected high bits\n"));
329 return refuse(pData, m, RCode_FormErr);
330 }
331
332 /*
333 * label of "llen" chars starts at offset "loff".
334 */
335 loff = off;
336 llen = c;
337 ++off;
338
339 if (loff + 1 + llen > mlen)
340 {
341 LogErr(("NAT: hostres: length byte points beyound packet boundary\n"));
342 return refuse(pData, m, RCode_FormErr);
343 }
344
345 if (llen == 0) /* end of the label list */
346 {
347 break;
348 }
349
350 /* do only minimal verification of the label */
351 while (off < loff + 1 + llen)
352 {
353 c = res->buf[off];
354 ++off;
355
356 if (c == '.')
357 {
358 LogErr(("NAT: hostres: dot inside label\n"));
359 return refuse(pData, m, RCode_FormErr);
360 }
361
362 if (c == '\0')
363 {
364 LogErr(("NAT: hostres: nul byte inside label\n"));
365 return refuse(pData, m, RCode_FormErr);
366 }
367 }
368
369 l = RTMemAllocZ(sizeof(*l));
370 l->buf = res->buf;
371 l->off = loff;
372 l->children = res->labels;
373 res->labels = l;
374 }
375
376 /*
377 * QTYPE and QCLASS
378 */
379 if (RT_UNLIKELY(off + 4 != mlen))
380 {
381 LogErr(("NAT: hostres: question too short / too long\n"));
382 return refuse(pData, m, RCode_FormErr);
383 }
384
385 memcpy(&qtype, &res->buf[off], sizeof(qtype));
386 qtype = RT_N2H_U16(qtype);
387 off += sizeof(qtype);
388
389 memcpy(&qclass, &res->buf[off], sizeof(qclass));
390 qclass = RT_N2H_U16(qclass);
391 off += sizeof(qclass);
392
393 if ( qclass != Class_IN
394 && qclass != Class_ANY)
395 {
396 LogErr(("NAT: hostres: unsupported qclass %d\n", qclass));
397 return refuse(pData, m, RCode_NotImp);
398 }
399
400 if ( qtype != Type_A
401 && qtype != Type_ANY)
402 {
403 LogErr(("NAT: hostres: unsupported qtype %d\n", qtype));
404 return refuse(pData, m, RCode_NotImp);
405 }
406
407 return resolve(pData, m, res, qname, qtype);
408}
409
410
411struct mbuf *
412resolve(PNATState pData, struct mbuf *m, struct response *res,
413 size_t qname, uint16_t qtype)
414{
415 struct dnsmsg_header *pHdr;
416 struct hostent *h;
417 size_t oend;
418 size_t nanswers;
419 ssize_t nbytes;
420 int i;
421
422 char name[DNS_MAX_NAME_LEN+1];
423
424 pHdr = (struct dnsmsg_header *)res->buf;
425 nanswers = 0;
426 oend = res->end;
427
428 strnlabels(name, sizeof(name), res->buf, qname);
429 LogDbg(("NAT: hostres: qname=\"%s\"\n", name));
430
431 h = gethostbyname(name);
432 if (h == NULL)
433 {
434 /* LogErr: h_errno */
435 return refuse(pData, m, RCode_NXDomain);
436 }
437
438#ifdef VBOX_WITH_DNSMAPPING_IN_HOSTRESOLVER
439 if (!LIST_EMPTY(&pData->DNSMapHead))
440 alterHostentWithDataFromDNSMap(pData, h);
441#endif
442
443 if ( h->h_name != NULL
444 && RTStrICmp(h->h_name, name) != 0)
445 {
446 LogDbg(("NAT: hostres: %s CNAME %s\n", name, h->h_name));
447 nbytes = append_cname(res, name, h->h_name);
448 if (nbytes > 0)
449 {
450 ++nanswers;
451 }
452 else
453 {
454 LogErr(("NAT: hostres: failed to add %s CNAME %s\n",
455 name, h->h_name));
456 if (nbytes < 0)
457 return refuse(pData, m, RCode_ServFail);
458 else
459 {
460 pHdr->tc = 1;
461 goto out;
462 }
463 }
464 }
465
466 /*
467 * XXX: TODO: rfc1034#section-3.6.2
468 *
469 * If the query is Type_ANY and the name is CNAME, we should only
470 * return the CNAME, but not the A RRs.
471 */
472 for (i = 0; h->h_addr_list[i] != NULL; ++i)
473 {
474 const char *cname = h->h_name ? h->h_name : name;
475 struct in_addr addr;
476
477 addr.s_addr = *(uint32_t *)h->h_addr_list[i];
478 nbytes = append_a(res, cname, addr);
479
480 if (nbytes > 0)
481 {
482 ++nanswers;
483 }
484 else
485 {
486 LogErr(("NAT: hostres: failed to add %s A %RTnaipv4\n",
487 cname, addr.s_addr));
488 if (nbytes < 0)
489 return refuse(pData, m, RCode_ServFail);
490 else
491 {
492 pHdr->tc = 1;
493 goto out;
494 }
495 }
496 }
497
498#if 0
499 /*
500 * It's not clear what to do with h_aliases.
501 *
502 * For names from the DNS it seems to contain the chain of CNAMEs,
503 * starting with the original qname from the question. So for
504 * them we'd need to reply with a chain of:
505 *
506 * h_aliases[i] CNAME h_aliases[i+1]
507 *
508 * OTOH, for the names from the hosts file it seems to contain all
509 * the names except the first one (which is considered primary and
510 * is reported as h_name). In which case the reply should be:
511 *
512 * h_aliases[i] CNAME h_name
513 *
514 * Obviously, we have no idea how the name was resolved, so we
515 * generate at most one CNAME for h_host (if differs) and ignore
516 * aliases altogehter.
517 */
518 for (i = 0; h->h_aliases[i] != NULL; ++i)
519 {
520 LogDbg(("NAT: hostres: ... %s\n", h->h_aliases[i]));
521 }
522#endif
523
524 out:
525 if (nanswers > 0)
526 {
527 int ok = m_append(pData, m, res->end - oend, (caddr_t)&res->buf[oend]);
528 if (!ok)
529 {
530 /* XXX: this may fail part way: restore old lenght, clear TC? */
531 return refuse(pData, m, RCode_ServFail);
532 }
533 pHdr->ancount = RT_H2N_U16(nanswers);
534 }
535 memcpy(mtod(m, char *), res->buf, sizeof(struct dnsmsg_header));
536 return m;
537}
538
539
540
541#define APPEND_PROLOGUE() \
542 ssize_t size = -1; \
543 size_t oend = res->end; \
544 ssize_t nbytes; \
545 do {} while (0)
546
547#define CHECKED(_append) \
548 do { \
549 nbytes = (_append); \
550 if (RT_UNLIKELY(nbytes <= 0)) \
551 { \
552 if (nbytes == 0) \
553 size = 0; \
554 goto out; \
555 } \
556 } while (0)
557
558#define APPEND_EPILOGUE() \
559 do { \
560 size = res->end - oend; \
561 out: \
562 if (RT_UNLIKELY(size <= 0)) \
563 res->end = oend; \
564 return size; \
565 } while (0)
566
567
568/*
569 * A RR - rfc1035#section-3.4.1
570 */
571static ssize_t
572append_a(struct response *res, const char *name, struct in_addr addr)
573{
574 APPEND_PROLOGUE();
575
576 CHECKED( append_rrhdr(res, name, Type_A, 3600) );
577 CHECKED( append_u16(res, RT_H2N_U16_C(sizeof(addr))) );
578 CHECKED( append_u32(res, addr.s_addr) );
579
580 APPEND_EPILOGUE();
581}
582
583
584/*
585 * CNAME RR - rfc1035#section-3.3.1
586 */
587static ssize_t
588append_cname(struct response *res, const char *name, const char *cname)
589{
590 size_t rdlpos;
591 uint16_t rdlength;
592
593 APPEND_PROLOGUE();
594
595 CHECKED( append_rrhdr(res, name, Type_CNAME, 3600) );
596
597 rdlpos = res->end;
598 CHECKED( append_u16(res, 0) ); /* RDLENGTH placeholder */
599
600 CHECKED( append_name(res, cname) );
601
602 rdlength = RT_H2N_U16(nbytes);
603 memcpy(&res->buf[rdlpos], &rdlength, sizeof(rdlength));
604
605 APPEND_EPILOGUE();
606}
607
608
609/*
610 * Append common RR header, up to but not including RDLENGTH and RDATA
611 * proper (rfc1035#section-3.2.1).
612 */
613static ssize_t
614append_rrhdr(struct response *res, const char *name, uint16_t type, uint32_t ttl)
615{
616 APPEND_PROLOGUE();
617
618 CHECKED( append_name(res, name) );
619 CHECKED( append_u16(res, RT_H2N_U16(type)) );
620 CHECKED( append_u16(res, RT_H2N_U16_C(Class_IN)) );
621 CHECKED( append_u32(res, RT_H2N_U32(ttl)) );
622
623 APPEND_EPILOGUE();
624}
625
626
627static ssize_t
628append_name(struct response *res, const char *name)
629{
630 ssize_t size, nbytes;
631 struct label *root;
632 struct label *haystack, *needle;
633 struct label *head, **neck;
634 struct label *tail, **graft;
635 uint8_t *buf;
636 size_t wr, oend;
637 const char *s;
638
639 size = -1;
640 oend = res->end;
641
642 /**
643 * Split new name into a list of labels encoding it into the
644 * temporary buffer.
645 */
646 root = NULL;
647
648 buf = RTMemAllocZ(strlen(name) + 1);
649 if (buf == NULL)
650 return -1;
651 wr = 0;
652
653 s = name;
654 while (*s != '\0') {
655 const char *part;
656 size_t poff, plen;
657 struct label *l;
658
659 part = s;
660 while (*s != '\0' && *s != '.')
661 ++s;
662
663 plen = s - part;
664
665 if (plen > DNS_MAX_LABEL_LEN)
666 {
667 LogErr(("NAT: hostres: name component too long\n"));
668 goto out;
669 }
670
671 if (*s == '.')
672 {
673 if (plen == 0)
674 {
675 LogErr(("NAT: hostres: empty name component\n"));
676 goto out;
677 }
678
679 ++s;
680 }
681
682 poff = wr;
683
684 buf[poff] = (uint8_t)plen; /* length byte */
685 ++wr;
686
687 memcpy(&buf[wr], part, plen); /* label text */
688 wr += plen;
689
690 l = RTMemAllocZ(sizeof(*l));
691 if (l == NULL)
692 goto out;
693
694 l->buf = buf;
695 l->off = poff;
696 l->children = root;
697 root = l;
698 }
699
700
701 /**
702 * Search for a tail that is already encoded in the message.
703 */
704 neck = &root; /* where needle head is connected */
705 needle = root;
706
707 tail = NULL; /* tail in the haystack */
708 graft = &res->labels;
709 haystack = res->labels;
710
711 while (needle != NULL && haystack != NULL)
712 {
713 size_t nlen, hlen;
714
715 nlen = needle->buf[needle->off];
716 Assert((nlen & DNS_LABEL_PTR) == 0);
717
718 hlen = haystack->buf[haystack->off];
719 Assert((hlen & DNS_LABEL_PTR) == 0);
720
721 if ( nlen == hlen
722 && RTStrNICmp((char *)&needle->buf[needle->off+1],
723 (char *)&haystack->buf[haystack->off+1],
724 nlen) == 0)
725 {
726 neck = &needle->children;
727 needle = needle->children;
728
729 tail = haystack;
730 graft = &haystack->children;
731 haystack = haystack->children;
732 }
733 else
734 {
735 haystack = haystack->sibling;
736 }
737 }
738
739
740 /**
741 * Head contains (in reverse) the prefix that needs to be encoded
742 * and added to the haystack. Tail points to existing suffix that
743 * can be compressed to a pointer into the haystack.
744 */
745 head = *neck;
746 if (head != NULL)
747 {
748 struct label *l;
749 size_t nlen, pfxlen, pfxdst;
750
751 nlen = needle->buf[head->off]; /* last component */
752 pfxlen = head->off + 1 + nlen; /* all prefix */
753 pfxdst = res->end; /* in response buffer */
754
755 /* copy new prefix into response buffer */
756 nbytes = append_bytes(res, buf, pfxlen);
757 if (nbytes <= 0)
758 {
759 if (nbytes == 0)
760 size = 0;
761 goto out;
762 }
763
764 /* adjust labels to point to the response */
765 for (l = head; l != NULL; l = l->children)
766 {
767 l->buf = res->buf;
768 l->off += pfxdst;
769 }
770
771 *neck = NULL; /* decapitate */
772
773 l = *graft; /* graft to the labels tree */
774 *graft = head;
775 head->sibling = l;
776 }
777
778 if (tail == NULL)
779 nbytes = append_u8(res, 0);
780 else
781 nbytes = append_u16(res, RT_H2N_U16((DNS_LABEL_PTR << 8) | tail->off));
782 if (nbytes <= 0)
783 {
784 if (nbytes == 0)
785 size = 0;
786 goto out;
787 }
788
789 size = res->end - oend;
790 out:
791 if (RT_UNLIKELY(size <= 0))
792 res->end = oend;
793 free_labels(root);
794 RTMemFree(buf);
795 return size;
796}
797
798
799static ssize_t
800append_u32(struct response *res, uint32_t value)
801{
802 return append_bytes(res, (uint8_t *)&value, sizeof(value));
803}
804
805
806static ssize_t
807append_u16(struct response *res, uint16_t value)
808{
809 return append_bytes(res, (uint8_t *)&value, sizeof(value));
810}
811
812
813static ssize_t
814append_u8(struct response *res, uint8_t value)
815{
816 return append_bytes(res, &value, sizeof(value));
817}
818
819
820static ssize_t
821append_bytes(struct response *res, uint8_t *p, size_t size)
822{
823 if (check_space(res, size) == 0)
824 return 0;
825
826 memcpy(&res->buf[res->end], p, size);
827 res->end += size;
828 return size;
829}
830
831
832static ssize_t
833check_space(struct response *res, size_t size)
834{
835 if ( size > sizeof(res->buf)
836 || res->end > sizeof(res->buf) - size)
837 return 0;
838
839 return size;
840}
841
842
843/*
844 * Convert a chain of labels to a C string.
845 *
846 * I'd rather use a custom formatter for e.g. %R[label] , but it needs
847 * two arguments and microsoft VC doesn't support compound literals.
848 */
849static void
850strnlabels(char *namebuf, size_t nbuflen, const uint8_t *msg, size_t off)
851{
852 size_t cb;
853 size_t llen;
854
855 namebuf[0] = '\0';
856 cb = 0;
857
858 llen = 0;
859
860 while (cb < nbuflen - 1) {
861 llen = msg[off];
862 if ((llen & DNS_LABEL_PTR) == DNS_LABEL_PTR)
863 {
864 off = ((llen & ~DNS_LABEL_PTR) << 8) | msg[off + 1];
865 llen = msg[off];
866 }
867
868 /* pointers to pointers should not happen */
869 if ((llen & DNS_LABEL_PTR) != 0)
870 {
871 cb += RTStrPrintf(namebuf + cb, nbuflen - cb, "[???]");
872 return;
873 }
874
875 if (llen == 0)
876 {
877 if (namebuf[0] == '\0')
878 cb += RTStrPrintf(namebuf + cb, nbuflen - cb, ".");
879 break;
880 }
881
882 if (namebuf[0] != '\0')
883 cb += RTStrPrintf(namebuf + cb, nbuflen - cb, ".");
884
885 cb += RTStrPrintf(namebuf + cb, nbuflen - cb,
886 "%.*s", llen, (char *)&msg[off+1]);
887 off = off + 1 + llen;
888 }
889}
890
891
892static void
893LogLabelsTree(const char *before, struct label *l, const char *after)
894{
895 size_t llen;
896
897 if (before != NULL)
898 LogDbg(("%s", before));
899
900 if (l == NULL)
901 {
902 LogDbg(("NULL%s", after ? after : ""));
903 return;
904 }
905
906 if (l->children)
907 LogDbg(("("));
908
909 if (l->buf != NULL)
910 {
911 llen = l->buf[l->off];
912 if ((llen & DNS_LABEL_PTR) == 0)
913 {
914 LogDbg(("\"%.*s\"@%zu", llen, &l->buf[l->off+1], l->off));
915 }
916 else
917 {
918 LogDbg(("<invalid byte 0t%zu/0x%zf at offset %zd>",
919 llen, llen, l->off));
920 }
921 }
922 else
923 {
924 LogDbg(("<*>"));
925 }
926
927 if (l->children)
928 LogLabelsTree(" ", l->children, ")");
929
930 if (l->sibling)
931 LogLabelsTree(" ", l->sibling, NULL);
932
933 if (after != NULL)
934 LogDbg(("%s", after));
935}
936
937
938static void
939free_labels(struct label *root)
940{
941 struct label TOP; /* traverse the tree with pointer reversal */
942 struct label *b, *f;
943
944 if (root == NULL)
945 return;
946
947 RT_ZERO(TOP);
948
949 b = &TOP;
950 f = root;
951
952 while (f != &TOP) {
953 if (f->children) { /* recurse left */
954 struct label *oldf = f;
955 struct label *newf = f->children;
956 oldf->children = b; /* reverse the pointer */
957 b = oldf;
958 f = newf;
959 }
960 else if (f->sibling) { /* turn right */
961 f->children = f->sibling;
962 f->sibling = NULL;
963 }
964 else { /* backtrack */
965 struct label *oldf = f; /* garbage */
966 struct label *oldb = b;
967 b = oldb->children;
968 oldb->children = NULL; /* oldf, but we are g/c'ing it */
969 f = oldb;
970
971 RTMemFree(oldf);
972 }
973 }
974}
975
976#ifdef VBOX_WITH_DNSMAPPING_IN_HOSTRESOLVER
977static bool isDnsMappingEntryMatchOrEqual2Str(const PDNSMAPPINGENTRY pDNSMapingEntry, const char *pcszString)
978{
979 return ( ( pDNSMapingEntry->pszCName
980 && !strcmp(pDNSMapingEntry->pszCName, pcszString))
981 || ( pDNSMapingEntry->pszPattern
982 && RTStrSimplePatternMultiMatch(pDNSMapingEntry->pszPattern, RTSTR_MAX, pcszString, RTSTR_MAX, NULL)));
983}
984
985static void alterHostentWithDataFromDNSMap(PNATState pData, struct hostent *pHostent)
986{
987 PDNSMAPPINGENTRY pDNSMapingEntry = NULL;
988 bool fMatch = false;
989 LIST_FOREACH(pDNSMapingEntry, &pData->DNSMapHead, MapList)
990 {
991 char **pszAlias = NULL;
992 if (isDnsMappingEntryMatchOrEqual2Str(pDNSMapingEntry, pHostent->h_name))
993 {
994 fMatch = true;
995 break;
996 }
997
998 for (pszAlias = pHostent->h_aliases; *pszAlias && !fMatch; pszAlias++)
999 {
1000 if (isDnsMappingEntryMatchOrEqual2Str(pDNSMapingEntry, *pszAlias))
1001 {
1002
1003 PDNSMAPPINGENTRY pDnsMapping = RTMemAllocZ(sizeof(DNSMAPPINGENTRY));
1004 fMatch = true;
1005 if (!pDnsMapping)
1006 {
1007 LogFunc(("Can't allocate DNSMAPPINGENTRY\n"));
1008 LogFlowFuncLeave();
1009 return;
1010 }
1011 pDnsMapping->u32IpAddress = pDNSMapingEntry->u32IpAddress;
1012 pDnsMapping->pszCName = RTStrDup(pHostent->h_name);
1013 if (!pDnsMapping->pszCName)
1014 {
1015 LogFunc(("Can't allocate enough room for %s\n", pHostent->h_name));
1016 RTMemFree(pDnsMapping);
1017 LogFlowFuncLeave();
1018 return;
1019 }
1020 LIST_INSERT_HEAD(&pData->DNSMapHead, pDnsMapping, MapList);
1021 LogRel(("NAT: User-defined mapping %s: %RTnaipv4 is registered\n",
1022 pDnsMapping->pszCName ? pDnsMapping->pszCName : pDnsMapping->pszPattern,
1023 pDnsMapping->u32IpAddress));
1024 }
1025 }
1026 if (fMatch)
1027 break;
1028 }
1029
1030 /* h_lenght is lenght of h_addr_list in bytes, so we check that we have enough space for IPv4 address */
1031 if ( fMatch
1032 && pHostent->h_length >= sizeof(uint32_t)
1033 && pDNSMapingEntry)
1034 {
1035 pHostent->h_length = 1;
1036 *(uint32_t *)pHostent->h_addr_list[0] = pDNSMapingEntry->u32IpAddress;
1037 }
1038
1039}
1040#endif
Note: See TracBrowser for help on using the repository browser.

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