VirtualBox

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

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

NAT: Host resolver - handle CNAME queries. When ANY query is received
for a CNAME, respond with just the CNAME, without A records, as per
RFC1034 section 3.6.2.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.3 KB
Line 
1/* $Id: hostres.c 59159 2015-12-16 16:23:53Z 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_CNAME
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 /*
445 * Emit CNAME record if canonical name differs from the qname.
446 */
447 if ( h->h_name != NULL
448 && RTStrICmp(h->h_name, name) != 0)
449 {
450 LogDbg(("NAT: hostres: %s CNAME %s\n", name, h->h_name));
451 nbytes = append_cname(res, name, h->h_name);
452 if (nbytes > 0)
453 {
454 ++nanswers;
455 }
456 else
457 {
458 LogErr(("NAT: hostres: failed to add %s CNAME %s\n",
459 name, h->h_name));
460 if (nbytes < 0)
461 return refuse(pData, m, RCode_ServFail);
462 else
463 {
464 pHdr->tc = 1;
465 goto out;
466 }
467 }
468
469 /*
470 * rfc1034#section-3.6.2 - ... a type CNAME or * query should
471 * return just the CNAME.
472 */
473 if (qtype == Type_CNAME || qtype == Type_ANY)
474 goto out;
475 }
476 else if (qtype == Type_CNAME)
477 {
478 LogErr(("NAT: hostres: %s is already canonical\n", name));
479 goto out; /* NB: RCode_NoError without an answer, not RCode_NXDomain */
480 }
481
482 /*
483 * Emit A records.
484 */
485 for (i = 0; h->h_addr_list[i] != NULL; ++i)
486 {
487 const char *cname = h->h_name ? h->h_name : name;
488 struct in_addr addr;
489
490 addr.s_addr = *(uint32_t *)h->h_addr_list[i];
491 nbytes = append_a(res, cname, addr);
492
493 if (nbytes > 0)
494 {
495 ++nanswers;
496 }
497 else
498 {
499 LogErr(("NAT: hostres: failed to add %s A %RTnaipv4\n",
500 cname, addr.s_addr));
501 if (nbytes < 0)
502 return refuse(pData, m, RCode_ServFail);
503 else
504 {
505 pHdr->tc = 1;
506 goto out;
507 }
508 }
509 }
510
511#if 0
512 /*
513 * It's not clear what to do with h_aliases.
514 *
515 * For names from the DNS it seems to contain the chain of CNAMEs,
516 * starting with the original qname from the question. So for
517 * them we'd need to reply with a chain of:
518 *
519 * h_aliases[i] CNAME h_aliases[i+1]
520 *
521 * OTOH, for the names from the hosts file it seems to contain all
522 * the names except the first one (which is considered primary and
523 * is reported as h_name). In which case the reply should be:
524 *
525 * h_aliases[i] CNAME h_name
526 *
527 * Obviously, we have no idea how the name was resolved, so we
528 * generate at most one CNAME for h_host (if differs) and ignore
529 * aliases altogehter.
530 */
531 for (i = 0; h->h_aliases[i] != NULL; ++i)
532 {
533 LogDbg(("NAT: hostres: ... %s\n", h->h_aliases[i]));
534 }
535#endif
536
537 out:
538 if (nanswers > 0)
539 {
540 int ok = m_append(pData, m, res->end - oend, (caddr_t)&res->buf[oend]);
541 if (!ok)
542 {
543 /* XXX: this may fail part way: restore old lenght, clear TC? */
544 return refuse(pData, m, RCode_ServFail);
545 }
546 pHdr->ancount = RT_H2N_U16(nanswers);
547 }
548 memcpy(mtod(m, char *), res->buf, sizeof(struct dnsmsg_header));
549 return m;
550}
551
552
553
554#define APPEND_PROLOGUE() \
555 ssize_t size = -1; \
556 size_t oend = res->end; \
557 ssize_t nbytes; \
558 do {} while (0)
559
560#define CHECKED(_append) \
561 do { \
562 nbytes = (_append); \
563 if (RT_UNLIKELY(nbytes <= 0)) \
564 { \
565 if (nbytes == 0) \
566 size = 0; \
567 goto out; \
568 } \
569 } while (0)
570
571#define APPEND_EPILOGUE() \
572 do { \
573 size = res->end - oend; \
574 out: \
575 if (RT_UNLIKELY(size <= 0)) \
576 res->end = oend; \
577 return size; \
578 } while (0)
579
580
581/*
582 * A RR - rfc1035#section-3.4.1
583 */
584static ssize_t
585append_a(struct response *res, const char *name, struct in_addr addr)
586{
587 APPEND_PROLOGUE();
588
589 CHECKED( append_rrhdr(res, name, Type_A, 3600) );
590 CHECKED( append_u16(res, RT_H2N_U16_C(sizeof(addr))) );
591 CHECKED( append_u32(res, addr.s_addr) );
592
593 APPEND_EPILOGUE();
594}
595
596
597/*
598 * CNAME RR - rfc1035#section-3.3.1
599 */
600static ssize_t
601append_cname(struct response *res, const char *name, const char *cname)
602{
603 size_t rdlpos;
604 uint16_t rdlength;
605
606 APPEND_PROLOGUE();
607
608 CHECKED( append_rrhdr(res, name, Type_CNAME, 3600) );
609
610 rdlpos = res->end;
611 CHECKED( append_u16(res, 0) ); /* RDLENGTH placeholder */
612
613 CHECKED( append_name(res, cname) );
614
615 rdlength = RT_H2N_U16(nbytes);
616 memcpy(&res->buf[rdlpos], &rdlength, sizeof(rdlength));
617
618 APPEND_EPILOGUE();
619}
620
621
622/*
623 * Append common RR header, up to but not including RDLENGTH and RDATA
624 * proper (rfc1035#section-3.2.1).
625 */
626static ssize_t
627append_rrhdr(struct response *res, const char *name, uint16_t type, uint32_t ttl)
628{
629 APPEND_PROLOGUE();
630
631 CHECKED( append_name(res, name) );
632 CHECKED( append_u16(res, RT_H2N_U16(type)) );
633 CHECKED( append_u16(res, RT_H2N_U16_C(Class_IN)) );
634 CHECKED( append_u32(res, RT_H2N_U32(ttl)) );
635
636 APPEND_EPILOGUE();
637}
638
639
640static ssize_t
641append_name(struct response *res, const char *name)
642{
643 ssize_t size, nbytes;
644 struct label *root;
645 struct label *haystack, *needle;
646 struct label *head, **neck;
647 struct label *tail, **graft;
648 uint8_t *buf;
649 size_t wr, oend;
650 const char *s;
651
652 size = -1;
653 oend = res->end;
654
655 /**
656 * Split new name into a list of labels encoding it into the
657 * temporary buffer.
658 */
659 root = NULL;
660
661 buf = RTMemAllocZ(strlen(name) + 1);
662 if (buf == NULL)
663 return -1;
664 wr = 0;
665
666 s = name;
667 while (*s != '\0') {
668 const char *part;
669 size_t poff, plen;
670 struct label *l;
671
672 part = s;
673 while (*s != '\0' && *s != '.')
674 ++s;
675
676 plen = s - part;
677
678 if (plen > DNS_MAX_LABEL_LEN)
679 {
680 LogErr(("NAT: hostres: name component too long\n"));
681 goto out;
682 }
683
684 if (*s == '.')
685 {
686 if (plen == 0)
687 {
688 LogErr(("NAT: hostres: empty name component\n"));
689 goto out;
690 }
691
692 ++s;
693 }
694
695 poff = wr;
696
697 buf[poff] = (uint8_t)plen; /* length byte */
698 ++wr;
699
700 memcpy(&buf[wr], part, plen); /* label text */
701 wr += plen;
702
703 l = RTMemAllocZ(sizeof(*l));
704 if (l == NULL)
705 goto out;
706
707 l->buf = buf;
708 l->off = poff;
709 l->children = root;
710 root = l;
711 }
712
713
714 /**
715 * Search for a tail that is already encoded in the message.
716 */
717 neck = &root; /* where needle head is connected */
718 needle = root;
719
720 tail = NULL; /* tail in the haystack */
721 graft = &res->labels;
722 haystack = res->labels;
723
724 while (needle != NULL && haystack != NULL)
725 {
726 size_t nlen, hlen;
727
728 nlen = needle->buf[needle->off];
729 Assert((nlen & DNS_LABEL_PTR) == 0);
730
731 hlen = haystack->buf[haystack->off];
732 Assert((hlen & DNS_LABEL_PTR) == 0);
733
734 if ( nlen == hlen
735 && RTStrNICmp((char *)&needle->buf[needle->off+1],
736 (char *)&haystack->buf[haystack->off+1],
737 nlen) == 0)
738 {
739 neck = &needle->children;
740 needle = needle->children;
741
742 tail = haystack;
743 graft = &haystack->children;
744 haystack = haystack->children;
745 }
746 else
747 {
748 haystack = haystack->sibling;
749 }
750 }
751
752
753 /**
754 * Head contains (in reverse) the prefix that needs to be encoded
755 * and added to the haystack. Tail points to existing suffix that
756 * can be compressed to a pointer into the haystack.
757 */
758 head = *neck;
759 if (head != NULL)
760 {
761 struct label *l;
762 size_t nlen, pfxlen, pfxdst;
763
764 nlen = needle->buf[head->off]; /* last component */
765 pfxlen = head->off + 1 + nlen; /* all prefix */
766 pfxdst = res->end; /* in response buffer */
767
768 /* copy new prefix into response buffer */
769 nbytes = append_bytes(res, buf, pfxlen);
770 if (nbytes <= 0)
771 {
772 if (nbytes == 0)
773 size = 0;
774 goto out;
775 }
776
777 /* adjust labels to point to the response */
778 for (l = head; l != NULL; l = l->children)
779 {
780 l->buf = res->buf;
781 l->off += pfxdst;
782 }
783
784 *neck = NULL; /* decapitate */
785
786 l = *graft; /* graft to the labels tree */
787 *graft = head;
788 head->sibling = l;
789 }
790
791 if (tail == NULL)
792 nbytes = append_u8(res, 0);
793 else
794 nbytes = append_u16(res, RT_H2N_U16((DNS_LABEL_PTR << 8) | tail->off));
795 if (nbytes <= 0)
796 {
797 if (nbytes == 0)
798 size = 0;
799 goto out;
800 }
801
802 size = res->end - oend;
803 out:
804 if (RT_UNLIKELY(size <= 0))
805 res->end = oend;
806 free_labels(root);
807 RTMemFree(buf);
808 return size;
809}
810
811
812static ssize_t
813append_u32(struct response *res, uint32_t value)
814{
815 return append_bytes(res, (uint8_t *)&value, sizeof(value));
816}
817
818
819static ssize_t
820append_u16(struct response *res, uint16_t value)
821{
822 return append_bytes(res, (uint8_t *)&value, sizeof(value));
823}
824
825
826static ssize_t
827append_u8(struct response *res, uint8_t value)
828{
829 return append_bytes(res, &value, sizeof(value));
830}
831
832
833static ssize_t
834append_bytes(struct response *res, uint8_t *p, size_t size)
835{
836 if (check_space(res, size) == 0)
837 return 0;
838
839 memcpy(&res->buf[res->end], p, size);
840 res->end += size;
841 return size;
842}
843
844
845static ssize_t
846check_space(struct response *res, size_t size)
847{
848 if ( size > sizeof(res->buf)
849 || res->end > sizeof(res->buf) - size)
850 return 0;
851
852 return size;
853}
854
855
856/*
857 * Convert a chain of labels to a C string.
858 *
859 * I'd rather use a custom formatter for e.g. %R[label] , but it needs
860 * two arguments and microsoft VC doesn't support compound literals.
861 */
862static void
863strnlabels(char *namebuf, size_t nbuflen, const uint8_t *msg, size_t off)
864{
865 size_t cb;
866 size_t llen;
867
868 namebuf[0] = '\0';
869 cb = 0;
870
871 llen = 0;
872
873 while (cb < nbuflen - 1) {
874 llen = msg[off];
875 if ((llen & DNS_LABEL_PTR) == DNS_LABEL_PTR)
876 {
877 off = ((llen & ~DNS_LABEL_PTR) << 8) | msg[off + 1];
878 llen = msg[off];
879 }
880
881 /* pointers to pointers should not happen */
882 if ((llen & DNS_LABEL_PTR) != 0)
883 {
884 cb += RTStrPrintf(namebuf + cb, nbuflen - cb, "[???]");
885 return;
886 }
887
888 if (llen == 0)
889 {
890 if (namebuf[0] == '\0')
891 cb += RTStrPrintf(namebuf + cb, nbuflen - cb, ".");
892 break;
893 }
894
895 if (namebuf[0] != '\0')
896 cb += RTStrPrintf(namebuf + cb, nbuflen - cb, ".");
897
898 cb += RTStrPrintf(namebuf + cb, nbuflen - cb,
899 "%.*s", llen, (char *)&msg[off+1]);
900 off = off + 1 + llen;
901 }
902}
903
904
905static void
906LogLabelsTree(const char *before, struct label *l, const char *after)
907{
908 size_t llen;
909
910 if (before != NULL)
911 LogDbg(("%s", before));
912
913 if (l == NULL)
914 {
915 LogDbg(("NULL%s", after ? after : ""));
916 return;
917 }
918
919 if (l->children)
920 LogDbg(("("));
921
922 if (l->buf != NULL)
923 {
924 llen = l->buf[l->off];
925 if ((llen & DNS_LABEL_PTR) == 0)
926 {
927 LogDbg(("\"%.*s\"@%zu", llen, &l->buf[l->off+1], l->off));
928 }
929 else
930 {
931 LogDbg(("<invalid byte 0t%zu/0x%zf at offset %zd>",
932 llen, llen, l->off));
933 }
934 }
935 else
936 {
937 LogDbg(("<*>"));
938 }
939
940 if (l->children)
941 LogLabelsTree(" ", l->children, ")");
942
943 if (l->sibling)
944 LogLabelsTree(" ", l->sibling, NULL);
945
946 if (after != NULL)
947 LogDbg(("%s", after));
948}
949
950
951static void
952free_labels(struct label *root)
953{
954 struct label TOP; /* traverse the tree with pointer reversal */
955 struct label *b, *f;
956
957 if (root == NULL)
958 return;
959
960 RT_ZERO(TOP);
961
962 b = &TOP;
963 f = root;
964
965 while (f != &TOP) {
966 if (f->children) { /* recurse left */
967 struct label *oldf = f;
968 struct label *newf = f->children;
969 oldf->children = b; /* reverse the pointer */
970 b = oldf;
971 f = newf;
972 }
973 else if (f->sibling) { /* turn right */
974 f->children = f->sibling;
975 f->sibling = NULL;
976 }
977 else { /* backtrack */
978 struct label *oldf = f; /* garbage */
979 struct label *oldb = b;
980 b = oldb->children;
981 oldb->children = NULL; /* oldf, but we are g/c'ing it */
982 f = oldb;
983
984 RTMemFree(oldf);
985 }
986 }
987}
988
989#ifdef VBOX_WITH_DNSMAPPING_IN_HOSTRESOLVER
990static bool isDnsMappingEntryMatchOrEqual2Str(const PDNSMAPPINGENTRY pDNSMapingEntry, const char *pcszString)
991{
992 return ( ( pDNSMapingEntry->pszCName
993 && !strcmp(pDNSMapingEntry->pszCName, pcszString))
994 || ( pDNSMapingEntry->pszPattern
995 && RTStrSimplePatternMultiMatch(pDNSMapingEntry->pszPattern, RTSTR_MAX, pcszString, RTSTR_MAX, NULL)));
996}
997
998static void alterHostentWithDataFromDNSMap(PNATState pData, struct hostent *pHostent)
999{
1000 PDNSMAPPINGENTRY pDNSMapingEntry = NULL;
1001 bool fMatch = false;
1002 LIST_FOREACH(pDNSMapingEntry, &pData->DNSMapHead, MapList)
1003 {
1004 char **pszAlias = NULL;
1005 if (isDnsMappingEntryMatchOrEqual2Str(pDNSMapingEntry, pHostent->h_name))
1006 {
1007 fMatch = true;
1008 break;
1009 }
1010
1011 for (pszAlias = pHostent->h_aliases; *pszAlias && !fMatch; pszAlias++)
1012 {
1013 if (isDnsMappingEntryMatchOrEqual2Str(pDNSMapingEntry, *pszAlias))
1014 {
1015
1016 PDNSMAPPINGENTRY pDnsMapping = RTMemAllocZ(sizeof(DNSMAPPINGENTRY));
1017 fMatch = true;
1018 if (!pDnsMapping)
1019 {
1020 LogFunc(("Can't allocate DNSMAPPINGENTRY\n"));
1021 LogFlowFuncLeave();
1022 return;
1023 }
1024 pDnsMapping->u32IpAddress = pDNSMapingEntry->u32IpAddress;
1025 pDnsMapping->pszCName = RTStrDup(pHostent->h_name);
1026 if (!pDnsMapping->pszCName)
1027 {
1028 LogFunc(("Can't allocate enough room for %s\n", pHostent->h_name));
1029 RTMemFree(pDnsMapping);
1030 LogFlowFuncLeave();
1031 return;
1032 }
1033 LIST_INSERT_HEAD(&pData->DNSMapHead, pDnsMapping, MapList);
1034 LogRel(("NAT: User-defined mapping %s: %RTnaipv4 is registered\n",
1035 pDnsMapping->pszCName ? pDnsMapping->pszCName : pDnsMapping->pszPattern,
1036 pDnsMapping->u32IpAddress));
1037 }
1038 }
1039 if (fMatch)
1040 break;
1041 }
1042
1043 /* h_lenght is lenght of h_addr_list in bytes, so we check that we have enough space for IPv4 address */
1044 if ( fMatch
1045 && pHostent->h_length >= sizeof(uint32_t)
1046 && pDNSMapingEntry)
1047 {
1048 pHostent->h_length = 1;
1049 *(uint32_t *)pHostent->h_addr_list[0] = pDNSMapingEntry->u32IpAddress;
1050 }
1051
1052}
1053#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