VirtualBox

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

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

NAT: Properly fix bitfields in struct dnsmsg_header so that "id" is a
normal member, not a bitfield.

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