Changeset 59142 in vbox for trunk/src/VBox/Devices/Network/slirp
- Timestamp:
- Dec 15, 2015 11:12:29 PM (9 years ago)
- Location:
- trunk/src/VBox/Devices/Network/slirp
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Network/slirp/hostres.c
r59063 r59142 28 28 #define DNS_CONTROL_PORT_NUMBER 53 29 29 /* see RFC 1035(4.1.1) */ 30 union dnsmsg_header 31 { 32 struct 33 { 34 unsigned id:16; 35 unsigned rd:1; 36 unsigned tc:1; 37 unsigned aa:1; 38 unsigned opcode:4; 39 unsigned qr:1; 40 unsigned rcode:4; 41 unsigned Z:3; 42 unsigned ra:1; 43 uint16_t qdcount; 44 uint16_t ancount; 45 uint16_t nscount; 46 uint16_t arcount; 47 } X; 48 uint16_t raw[6]; 30 struct dnsmsg_header 31 { 32 uint16_t id; 33 34 /* XXX: endianness */ 35 unsigned rd:1; 36 unsigned tc:1; 37 unsigned aa:1; 38 unsigned opcode:4; 39 unsigned qr:1; 40 unsigned rcode:4; 41 unsigned Z:3; 42 unsigned ra:1; 43 44 uint16_t qdcount; 45 uint16_t ancount; 46 uint16_t nscount; 47 uint16_t arcount; 49 48 }; 50 AssertCompileSize(union dnsmsg_header, 12); 51 52 struct dns_meta_data 53 { 54 uint16_t type; 55 uint16_t class; 49 AssertCompileSize(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 */ 85 struct label 86 { 87 const uint8_t *buf; 88 ssize_t off; 89 struct label *children; 90 struct label *sibling; 56 91 }; 57 92 58 struct dnsmsg_answer 59 { 60 uint16_t name; 61 struct dns_meta_data meta; 62 uint16_t ttl[2]; 63 uint16_t rdata_len; 64 uint8_t rdata[1]; /* depends on value at rdata_len */ 93 94 /* 95 * A structure to build DNS response. 96 */ 97 struct 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]; 65 105 }; 66 106 67 /* see RFC 1035(4.1) */ 68 static void CStr2QStr(const char *pcszStr, char *pszQStr, size_t cQStr); 69 static void QStr2CStr(const char *pcszQStr, char *pszStr, size_t cStr); 107 108 static int verify_header(PNATState pData, struct mbuf **pMBuf); 109 static struct mbuf *respond(PNATState pData, struct mbuf *m, struct response *res); 110 struct mbuf *resolve(PNATState pData, struct mbuf *m, struct response *res, size_t qname, uint16_t qtype); 111 struct mbuf *refuse(PNATState pData, struct mbuf *m, unsigned int rcode); 112 static ssize_t append_a(struct response *res, const char *name, struct in_addr addr); 113 static ssize_t append_cname(struct response *res, const char *name, const char *cname); 114 static ssize_t append_rrhdr(struct response *res, const char *name, uint16_t type, uint32_t ttl); 115 static ssize_t append_name(struct response *res, const char *name); 116 static ssize_t append_u32(struct response *res, uint32_t value); 117 static ssize_t append_u16(struct response *res, uint16_t value); 118 static ssize_t append_u8(struct response *res, uint8_t value); 119 static ssize_t append_bytes(struct response *res, uint8_t *p, size_t size); 120 static ssize_t check_space(struct response *res, size_t size); 121 122 static void strnlabels(char *namebuf, size_t nbuflen, const uint8_t *msg, size_t off); 123 124 static void LogLabelsTree(const char *before, struct label *l, const char *after); 125 static void free_labels(struct label *root); 126 70 127 #ifdef VBOX_WITH_DNSMAPPING_IN_HOSTRESOLVER 71 128 static void alterHostentWithDataFromDNSMap(PNATState pData, struct hostent *pHostent); 72 129 #endif 73 130 74 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 140 struct mbuf * 141 hostresolver(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 164 struct mbuf * 165 refuse(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 179 static int 180 verify_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 277 static struct mbuf * 278 respond(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 412 struct mbuf * 413 resolve(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 */ 572 static ssize_t 573 append_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 */ 588 static ssize_t 589 append_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 */ 614 static ssize_t 615 append_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 628 static ssize_t 629 append_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 803 static ssize_t 804 append_u32(struct response *res, uint32_t value) 805 { 806 return append_bytes(res, (uint8_t *)&value, sizeof(value)); 807 } 808 809 810 static ssize_t 811 append_u16(struct response *res, uint16_t value) 812 { 813 return append_bytes(res, (uint8_t *)&value, sizeof(value)); 814 } 815 816 817 static ssize_t 818 append_u8(struct response *res, uint8_t value) 819 { 820 return append_bytes(res, &value, sizeof(value)); 821 } 822 823 824 static ssize_t 825 append_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 836 static ssize_t 837 check_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 */ 75 853 static void 76 doanswer(struct mbuf *m, struct hostent *pHostent) 77 { 78 union dnsmsg_header *pHdr; 79 int i; 80 81 pHdr = mtod(m, union dnsmsg_header *); 82 83 if (!pHostent) 84 { 85 pHdr->X.qr = 1; /* response */ 86 pHdr->X.aa = 1; 87 pHdr->X.rd = 1; 88 pHdr->X.rcode = 3; 854 strnlabels(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 896 static void 897 LogLabelsTree(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 } 89 925 } 90 926 else 91 927 { 92 char *answers; 93 uint16_t off; 94 char **cstr; 95 char *c; 96 size_t anslen = 0; 97 uint16_t addr_off = (uint16_t)~0; 98 struct dns_meta_data *meta; 99 100 /* answers zone lays after query in response packet */ 101 answers = (char *)pHdr + m->m_len; 102 103 off = (char *)&pHdr[1] - (char *)pHdr; 104 off |= (0x3 << 14); 105 106 /* add aliases */ 107 for (cstr = pHostent->h_aliases; cstr && *cstr; cstr++) 108 { 109 uint16_t len; 110 struct dnsmsg_answer *ans = (struct dnsmsg_answer *)answers; 111 ans->name = htons(off); 112 ans->meta.type = htons(5); /* CNAME */ 113 ans->meta.class = htons(1); 114 *(uint32_t *)ans->ttl = htonl(3600); /* 1h */ 115 c = (addr_off == (uint16_t)~0 ? pHostent->h_name : *cstr); 116 len = strlen(c) + 2; 117 ans->rdata_len = htons(len); 118 ans->rdata[len - 1] = 0; 119 CStr2QStr(c, (char *)ans->rdata, len); 120 off = (char *)&ans->rdata - (char *)pHdr; 121 off |= (0x3 << 14); 122 if (addr_off == (uint16_t)~0) 123 addr_off = off; 124 answers = (char *)&ans[1] + len - 2; /* note: 1 symbol already counted */ 125 anslen += sizeof(struct dnsmsg_answer) + len - 2; 126 pHdr->X.ancount++; 127 } 128 129 /* add addresses */ 130 for(i = 0; i < pHostent->h_length && pHostent->h_addr_list[i] != NULL; ++i) 131 { 132 struct dnsmsg_answer *ans = (struct dnsmsg_answer *)answers; 133 134 ans->name = htons(off); 135 ans->meta.type = htons(1); 136 ans->meta.class = htons(1); 137 *(uint32_t *)ans->ttl = htonl(3600); /* 1h */ 138 ans->rdata_len = htons(4); /* IPv4 */ 139 *(uint32_t *)ans->rdata = *(uint32_t *)pHostent->h_addr_list[i]; 140 answers = (char *)&ans[1] + 2; 141 anslen += sizeof(struct dnsmsg_answer) + 3; 142 pHdr->X.ancount++; 143 } 144 pHdr->X.qr = 1; /* response */ 145 pHdr->X.aa = 1; 146 pHdr->X.rd = 1; 147 pHdr->X.ra = 1; 148 pHdr->X.rcode = 0; 149 HTONS(pHdr->X.ancount); 150 151 m->m_len += anslen; 152 } 153 } 154 155 int 156 hostresolver(PNATState pData, struct mbuf *m) 157 { 158 int i; 159 /* Parse dns request */ 160 char *qw_qname = NULL; 161 struct hostent *pHostent = NULL; 162 char pszCname[255]; 163 int cname_len = 0; 164 struct dns_meta_data *meta; 165 166 union dnsmsg_header *pHdr = NULL; 167 168 pHdr = mtod(m, union dnsmsg_header *); 169 170 if (pHdr->X.qr == 1) 171 return 1; /* this is respose */ 172 173 memset(pszCname, 0, sizeof(pszCname)); 174 qw_qname = (char *)&pHdr[1]; 175 176 if ((ntohs(pHdr->X.qdcount) != 1)) 177 { 178 static bool fMultiWarn; 179 if (!fMultiWarn) 180 { 181 LogRel(("NAT: alias_dns: Multiple queries isn't supported\n")); 182 fMultiWarn = true; 183 } 184 return 1; 185 } 186 187 { 188 meta = (struct dns_meta_data *)(qw_qname + strlen(qw_qname) + 1); 189 Log(("pszQname:%s qtype:%hd qclass:%hd\n", 190 qw_qname, ntohs(meta->type), ntohs(meta->class))); 191 192 QStr2CStr(qw_qname, pszCname, sizeof(pszCname)); 193 cname_len = RTStrNLen(pszCname, sizeof(pszCname)); 194 /* Some guests like win-xp adds _dot_ after host name 195 * and after domain name (not passed with host resolver) 196 * that confuses host resolver. 197 */ 198 if ( cname_len > 2 199 && pszCname[cname_len - 1] == '.' 200 && pszCname[cname_len - 2] == '.') 201 { 202 pszCname[cname_len - 1] = 0; 203 pszCname[cname_len - 2] = 0; 204 } 205 pHostent = gethostbyname(pszCname); 206 #ifdef VBOX_WITH_DNSMAPPING_IN_HOSTRESOLVER 207 if ( pHostent 208 && !LIST_EMPTY(&pData->DNSMapHead)) 209 alterHostentWithDataFromDNSMap(pData, pHostent); 210 #endif 211 doanswer(m, pHostent); 212 } 213 214 return 0; 215 } 216 217 /* 218 * qstr is z-string with -dot- replaced with \count to next -dot- 219 * e.g. ya.ru is \02ya\02ru 220 * Note: it's assumed that caller allocates buffer for cstr 221 */ 222 static void QStr2CStr(const char *pcszQStr, char *pszStr, size_t cStr) 223 { 224 const char *q; 225 char *c; 226 size_t cLen = 0; 227 228 Assert(cStr > 0); 229 for (q = pcszQStr, c = pszStr; *q != '\0' && cLen < cStr-1; q++, cLen++) 230 { 231 if ( isalpha(*q) 232 || isdigit(*q) 233 || *q == '-' 234 || *q == '_') 235 { 236 *c = *q; 237 c++; 238 } 239 else if (c != &pszStr[0]) 240 { 241 *c = '.'; 242 c++; 243 } 244 } 245 *c = '\0'; 246 } 247 248 /* 249 * 250 */ 251 static void CStr2QStr(const char *pcszStr, char *pszQStr, size_t cQStr) 252 { 253 const char *c; 254 const char *pc; 255 char *q; 256 size_t cLen = 0; 257 258 Assert(cQStr > 0); 259 for (c = pcszStr, q = pszQStr; *c != '\0' && cLen < cQStr-1; q++, cLen++) 260 { 261 /* at the begining or at -dot- position */ 262 if (*c == '.' || (c == pcszStr && q == pszQStr)) 263 { 264 if (c != pcszStr) 265 c++; 266 pc = strchr(c, '.'); 267 *q = pc ? (pc - c) : strlen(c); 268 } 269 else 270 { 271 *q = *c; 272 c++; 273 } 274 } 275 *q = '\0'; 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 942 static void 943 free_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 } 276 978 } 277 979 -
trunk/src/VBox/Devices/Network/slirp/slirp.h
r59063 r59142 352 352 353 353 /* hostres.c */ 354 inthostresolver(PNATState, struct mbuf *);354 struct mbuf *hostresolver(PNATState, struct mbuf *); 355 355 356 356 /*slirp.c*/
Note:
See TracChangeset
for help on using the changeset viewer.