1 /* $OpenBSD: dns.c,v 1.83 2015/10/28 07:28:13 gilles Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> 5 * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net> 6 * Copyright (c) 2011-2014 Eric Faurot <eric@faurot.net> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/socket.h> 23 #include <sys/tree.h> 24 #include <sys/queue.h> 25 #include <sys/uio.h> 26 27 #include <netinet/in.h> 28 #include <arpa/inet.h> 29 #include <arpa/nameser.h> 30 #include <netdb.h> 31 32 #include <asr.h> 33 #include <event.h> 34 #include <imsg.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <limits.h> 39 40 #include "smtpd.h" 41 #include "log.h" 42 43 struct dns_lookup { 44 struct dns_session *session; 45 int preference; 46 }; 47 48 struct dns_session { 49 struct mproc *p; 50 uint64_t reqid; 51 int type; 52 char name[HOST_NAME_MAX+1]; 53 size_t mxfound; 54 int error; 55 int refcount; 56 }; 57 58 static void dns_lookup_host(struct dns_session *, const char *, int); 59 static void dns_dispatch_host(struct asr_result *, void *); 60 static void dns_dispatch_ptr(struct asr_result *, void *); 61 static void dns_dispatch_mx(struct asr_result *, void *); 62 static void dns_dispatch_mx_preference(struct asr_result *, void *); 63 64 struct unpack { 65 const char *buf; 66 size_t len; 67 size_t offset; 68 const char *err; 69 }; 70 71 struct dns_header { 72 uint16_t id; 73 uint16_t flags; 74 uint16_t qdcount; 75 uint16_t ancount; 76 uint16_t nscount; 77 uint16_t arcount; 78 }; 79 80 struct dns_query { 81 char q_dname[MAXDNAME]; 82 uint16_t q_type; 83 uint16_t q_class; 84 }; 85 86 struct dns_rr { 87 char rr_dname[MAXDNAME]; 88 uint16_t rr_type; 89 uint16_t rr_class; 90 uint32_t rr_ttl; 91 union { 92 struct { 93 char cname[MAXDNAME]; 94 } cname; 95 struct { 96 uint16_t preference; 97 char exchange[MAXDNAME]; 98 } mx; 99 struct { 100 char nsname[MAXDNAME]; 101 } ns; 102 struct { 103 char ptrname[MAXDNAME]; 104 } ptr; 105 struct { 106 char mname[MAXDNAME]; 107 char rname[MAXDNAME]; 108 uint32_t serial; 109 uint32_t refresh; 110 uint32_t retry; 111 uint32_t expire; 112 uint32_t minimum; 113 } soa; 114 struct { 115 struct in_addr addr; 116 } in_a; 117 struct { 118 struct in6_addr addr6; 119 } in_aaaa; 120 struct { 121 uint16_t rdlen; 122 const void *rdata; 123 } other; 124 } rr; 125 }; 126 127 static char *print_dname(const char *, char *, size_t); 128 static ssize_t dname_expand(const unsigned char *, size_t, size_t, size_t *, 129 char *, size_t); 130 static int unpack_data(struct unpack *, void *, size_t); 131 static int unpack_u16(struct unpack *, uint16_t *); 132 static int unpack_u32(struct unpack *, uint32_t *); 133 static int unpack_inaddr(struct unpack *, struct in_addr *); 134 static int unpack_in6addr(struct unpack *, struct in6_addr *); 135 static int unpack_dname(struct unpack *, char *, size_t); 136 static void unpack_init(struct unpack *, const char *, size_t); 137 static int unpack_header(struct unpack *, struct dns_header *); 138 static int unpack_query(struct unpack *, struct dns_query *); 139 static int unpack_rr(struct unpack *, struct dns_rr *); 140 141 142 static int 143 domainname_is_addr(const char *s, struct sockaddr *sa, socklen_t *sl) 144 { 145 struct addrinfo hints, *res; 146 socklen_t sl2; 147 size_t l; 148 char buf[SMTPD_MAXDOMAINPARTSIZE]; 149 int i6, error; 150 151 if (*s != '[') 152 return (0); 153 154 i6 = (strncasecmp("[IPv6:", s, 6) == 0); 155 s += i6 ? 6 : 1; 156 157 l = strlcpy(buf, s, sizeof(buf)); 158 if (l >= sizeof(buf) || l == 0 || buf[l - 1] != ']') 159 return (0); 160 161 buf[l - 1] = '\0'; 162 memset(&hints, 0, sizeof(hints)); 163 hints.ai_flags = AI_NUMERICHOST; 164 hints.ai_socktype = SOCK_STREAM; 165 if (i6) 166 hints.ai_family = AF_INET6; 167 168 res = NULL; 169 if ((error = getaddrinfo(buf, NULL, &hints, &res))) { 170 log_warnx("getaddrinfo: %s", gai_strerror(error)); 171 } 172 173 if (!res) 174 return (0); 175 176 if (sa && sl) { 177 sl2 = *sl; 178 if (sl2 > res->ai_addrlen) 179 sl2 = res->ai_addrlen; 180 memmove(sa, res->ai_addr, sl2); 181 *sl = res->ai_addrlen; 182 } 183 184 freeaddrinfo(res); 185 return (1); 186 } 187 188 void 189 dns_imsg(struct mproc *p, struct imsg *imsg) 190 { 191 struct sockaddr_storage ss; 192 struct dns_session *s; 193 struct sockaddr *sa; 194 struct asr_query *as; 195 struct msg m; 196 const char *domain, *mx, *host; 197 socklen_t sl; 198 199 s = xcalloc(1, sizeof *s, "dns_imsg"); 200 s->type = imsg->hdr.type; 201 s->p = p; 202 203 m_msg(&m, imsg); 204 m_get_id(&m, &s->reqid); 205 206 switch (s->type) { 207 208 case IMSG_MTA_DNS_HOST: 209 m_get_string(&m, &host); 210 m_end(&m); 211 dns_lookup_host(s, host, -1); 212 return; 213 214 case IMSG_MTA_DNS_PTR: 215 case IMSG_SMTP_DNS_PTR: 216 sa = (struct sockaddr *)&ss; 217 m_get_sockaddr(&m, sa); 218 m_end(&m); 219 as = getnameinfo_async(sa, sa->sa_len, s->name, sizeof(s->name), 220 NULL, 0, 0, NULL); 221 event_asr_run(as, dns_dispatch_ptr, s); 222 return; 223 224 case IMSG_MTA_DNS_MX: 225 m_get_string(&m, &domain); 226 m_end(&m); 227 (void)strlcpy(s->name, domain, sizeof(s->name)); 228 229 sa = (struct sockaddr *)&ss; 230 sl = sizeof(ss); 231 232 if (domainname_is_addr(domain, sa, &sl)) { 233 m_create(s->p, IMSG_MTA_DNS_HOST, 0, 0, -1); 234 m_add_id(s->p, s->reqid); 235 m_add_sockaddr(s->p, sa); 236 m_add_int(s->p, -1); 237 m_close(s->p); 238 239 m_create(s->p, IMSG_MTA_DNS_HOST_END, 0, 0, -1); 240 m_add_id(s->p, s->reqid); 241 m_add_int(s->p, DNS_OK); 242 m_close(s->p); 243 free(s); 244 return; 245 } 246 247 as = res_query_async(s->name, C_IN, T_MX, NULL); 248 if (as == NULL) { 249 log_warn("warn: req_query_async: %s", s->name); 250 m_create(s->p, IMSG_MTA_DNS_HOST_END, 0, 0, -1); 251 m_add_id(s->p, s->reqid); 252 m_add_int(s->p, DNS_EINVAL); 253 m_close(s->p); 254 free(s); 255 return; 256 } 257 258 event_asr_run(as, dns_dispatch_mx, s); 259 return; 260 261 case IMSG_MTA_DNS_MX_PREFERENCE: 262 m_get_string(&m, &domain); 263 m_get_string(&m, &mx); 264 m_end(&m); 265 (void)strlcpy(s->name, mx, sizeof(s->name)); 266 267 as = res_query_async(domain, C_IN, T_MX, NULL); 268 if (as == NULL) { 269 m_create(s->p, IMSG_MTA_DNS_MX_PREFERENCE, 0, 0, -1); 270 m_add_id(s->p, s->reqid); 271 m_add_int(s->p, DNS_ENOTFOUND); 272 m_close(s->p); 273 free(s); 274 return; 275 } 276 277 event_asr_run(as, dns_dispatch_mx_preference, s); 278 return; 279 280 default: 281 log_warnx("warn: bad dns request %d", s->type); 282 fatal(NULL); 283 } 284 } 285 286 static void 287 dns_dispatch_host(struct asr_result *ar, void *arg) 288 { 289 struct dns_session *s; 290 struct dns_lookup *lookup = arg; 291 struct addrinfo *ai; 292 293 s = lookup->session; 294 295 for (ai = ar->ar_addrinfo; ai; ai = ai->ai_next) { 296 s->mxfound++; 297 m_create(s->p, IMSG_MTA_DNS_HOST, 0, 0, -1); 298 m_add_id(s->p, s->reqid); 299 m_add_sockaddr(s->p, ai->ai_addr); 300 m_add_int(s->p, lookup->preference); 301 m_close(s->p); 302 } 303 free(lookup); 304 if (ar->ar_addrinfo) 305 freeaddrinfo(ar->ar_addrinfo); 306 307 if (ar->ar_gai_errno) 308 s->error = ar->ar_gai_errno; 309 310 if (--s->refcount) 311 return; 312 313 m_create(s->p, IMSG_MTA_DNS_HOST_END, 0, 0, -1); 314 m_add_id(s->p, s->reqid); 315 m_add_int(s->p, s->mxfound ? DNS_OK : DNS_ENOTFOUND); 316 m_close(s->p); 317 free(s); 318 } 319 320 static void 321 dns_dispatch_ptr(struct asr_result *ar, void *arg) 322 { 323 struct dns_session *s = arg; 324 325 /* The error code could be more precise, but we don't currently care */ 326 m_create(s->p, s->type, 0, 0, -1); 327 m_add_id(s->p, s->reqid); 328 m_add_int(s->p, ar->ar_gai_errno ? DNS_ENOTFOUND : DNS_OK); 329 if (ar->ar_gai_errno == 0) 330 m_add_string(s->p, s->name); 331 m_close(s->p); 332 free(s); 333 } 334 335 static void 336 dns_dispatch_mx(struct asr_result *ar, void *arg) 337 { 338 struct dns_session *s = arg; 339 struct unpack pack; 340 struct dns_header h; 341 struct dns_query q; 342 struct dns_rr rr; 343 char buf[512]; 344 size_t found; 345 346 if (ar->ar_h_errno && ar->ar_h_errno != NO_DATA) { 347 348 m_create(s->p, IMSG_MTA_DNS_HOST_END, 0, 0, -1); 349 m_add_id(s->p, s->reqid); 350 if (ar->ar_rcode == NXDOMAIN) 351 m_add_int(s->p, DNS_ENONAME); 352 else if (ar->ar_h_errno == NO_RECOVERY) 353 m_add_int(s->p, DNS_EINVAL); 354 else 355 m_add_int(s->p, DNS_RETRY); 356 m_close(s->p); 357 free(s); 358 free(ar->ar_data); 359 return; 360 } 361 362 unpack_init(&pack, ar->ar_data, ar->ar_datalen); 363 unpack_header(&pack, &h); 364 unpack_query(&pack, &q); 365 366 found = 0; 367 for (; h.ancount; h.ancount--) { 368 unpack_rr(&pack, &rr); 369 if (rr.rr_type != T_MX) 370 continue; 371 print_dname(rr.rr.mx.exchange, buf, sizeof(buf)); 372 buf[strlen(buf) - 1] = '\0'; 373 dns_lookup_host(s, buf, rr.rr.mx.preference); 374 found++; 375 } 376 free(ar->ar_data); 377 378 /* fallback to host if no MX is found. */ 379 if (found == 0) 380 dns_lookup_host(s, s->name, 0); 381 } 382 383 static void 384 dns_dispatch_mx_preference(struct asr_result *ar, void *arg) 385 { 386 struct dns_session *s = arg; 387 struct unpack pack; 388 struct dns_header h; 389 struct dns_query q; 390 struct dns_rr rr; 391 char buf[512]; 392 int error; 393 394 if (ar->ar_h_errno) { 395 if (ar->ar_rcode == NXDOMAIN) 396 error = DNS_ENONAME; 397 else if (ar->ar_h_errno == NO_RECOVERY 398 || ar->ar_h_errno == NO_DATA) 399 error = DNS_EINVAL; 400 else 401 error = DNS_RETRY; 402 } 403 else { 404 error = DNS_ENOTFOUND; 405 unpack_init(&pack, ar->ar_data, ar->ar_datalen); 406 unpack_header(&pack, &h); 407 unpack_query(&pack, &q); 408 for (; h.ancount; h.ancount--) { 409 unpack_rr(&pack, &rr); 410 if (rr.rr_type != T_MX) 411 continue; 412 print_dname(rr.rr.mx.exchange, buf, sizeof(buf)); 413 buf[strlen(buf) - 1] = '\0'; 414 if (!strcasecmp(s->name, buf)) { 415 error = DNS_OK; 416 break; 417 } 418 } 419 } 420 421 free(ar->ar_data); 422 423 m_create(s->p, IMSG_MTA_DNS_MX_PREFERENCE, 0, 0, -1); 424 m_add_id(s->p, s->reqid); 425 m_add_int(s->p, error); 426 if (error == DNS_OK) 427 m_add_int(s->p, rr.rr.mx.preference); 428 m_close(s->p); 429 free(s); 430 } 431 432 static void 433 dns_lookup_host(struct dns_session *s, const char *host, int preference) 434 { 435 struct dns_lookup *lookup; 436 struct addrinfo hints; 437 char hostcopy[HOST_NAME_MAX+1]; 438 char *p; 439 void *as; 440 441 lookup = xcalloc(1, sizeof *lookup, "dns_lookup_host"); 442 lookup->preference = preference; 443 lookup->session = s; 444 s->refcount++; 445 446 if (*host == '[') { 447 if (strncasecmp("[IPv6:", host, 6) == 0) 448 host += 6; 449 else 450 host += 1; 451 (void)strlcpy(hostcopy, host, sizeof hostcopy); 452 p = strchr(hostcopy, ']'); 453 if (p) 454 *p = 0; 455 host = hostcopy; 456 } 457 458 memset(&hints, 0, sizeof(hints)); 459 hints.ai_flags = AI_ADDRCONFIG; 460 hints.ai_family = PF_UNSPEC; 461 hints.ai_socktype = SOCK_STREAM; 462 as = getaddrinfo_async(host, NULL, &hints, NULL); 463 event_asr_run(as, dns_dispatch_host, lookup); 464 } 465 466 static char * 467 print_dname(const char *_dname, char *buf, size_t max) 468 { 469 const unsigned char *dname = _dname; 470 char *res; 471 size_t left, n, count; 472 473 if (_dname[0] == 0) { 474 (void)strlcpy(buf, ".", max); 475 return buf; 476 } 477 478 res = buf; 479 left = max - 1; 480 for (n = 0; dname[0] && left; n += dname[0]) { 481 count = (dname[0] < (left - 1)) ? dname[0] : (left - 1); 482 memmove(buf, dname + 1, count); 483 dname += dname[0] + 1; 484 left -= count; 485 buf += count; 486 if (left) { 487 left -= 1; 488 *buf++ = '.'; 489 } 490 } 491 buf[0] = 0; 492 493 return (res); 494 } 495 496 static ssize_t 497 dname_expand(const unsigned char *data, size_t len, size_t offset, 498 size_t *newoffset, char *dst, size_t max) 499 { 500 size_t n, count, end, ptr, start; 501 ssize_t res; 502 503 if (offset >= len) 504 return (-1); 505 506 res = 0; 507 end = start = offset; 508 509 for (; (n = data[offset]); ) { 510 if ((n & 0xc0) == 0xc0) { 511 if (offset + 2 > len) 512 return (-1); 513 ptr = 256 * (n & ~0xc0) + data[offset + 1]; 514 if (ptr >= start) 515 return (-1); 516 if (end < offset + 2) 517 end = offset + 2; 518 offset = start = ptr; 519 continue; 520 } 521 if (offset + n + 1 > len) 522 return (-1); 523 524 /* copy n + at offset+1 */ 525 if (dst != NULL && max != 0) { 526 count = (max < n + 1) ? (max) : (n + 1); 527 memmove(dst, data + offset, count); 528 dst += count; 529 max -= count; 530 } 531 res += n + 1; 532 offset += n + 1; 533 if (end < offset) 534 end = offset; 535 } 536 if (end < offset + 1) 537 end = offset + 1; 538 539 if (dst != NULL && max != 0) 540 dst[0] = 0; 541 if (newoffset) 542 *newoffset = end; 543 return (res + 1); 544 } 545 546 void 547 unpack_init(struct unpack *unpack, const char *buf, size_t len) 548 { 549 unpack->buf = buf; 550 unpack->len = len; 551 unpack->offset = 0; 552 unpack->err = NULL; 553 } 554 555 static int 556 unpack_data(struct unpack *p, void *data, size_t len) 557 { 558 if (p->err) 559 return (-1); 560 561 if (p->len - p->offset < len) { 562 p->err = "too short"; 563 return (-1); 564 } 565 566 memmove(data, p->buf + p->offset, len); 567 p->offset += len; 568 569 return (0); 570 } 571 572 static int 573 unpack_u16(struct unpack *p, uint16_t *u16) 574 { 575 if (unpack_data(p, u16, 2) == -1) 576 return (-1); 577 578 *u16 = ntohs(*u16); 579 580 return (0); 581 } 582 583 static int 584 unpack_u32(struct unpack *p, uint32_t *u32) 585 { 586 if (unpack_data(p, u32, 4) == -1) 587 return (-1); 588 589 *u32 = ntohl(*u32); 590 591 return (0); 592 } 593 594 static int 595 unpack_inaddr(struct unpack *p, struct in_addr *a) 596 { 597 return (unpack_data(p, a, 4)); 598 } 599 600 static int 601 unpack_in6addr(struct unpack *p, struct in6_addr *a6) 602 { 603 return (unpack_data(p, a6, 16)); 604 } 605 606 static int 607 unpack_dname(struct unpack *p, char *dst, size_t max) 608 { 609 ssize_t e; 610 611 if (p->err) 612 return (-1); 613 614 e = dname_expand(p->buf, p->len, p->offset, &p->offset, dst, max); 615 if (e == -1) { 616 p->err = "bad domain name"; 617 return (-1); 618 } 619 if (e < 0 || e > MAXDNAME) { 620 p->err = "domain name too long"; 621 return (-1); 622 } 623 624 return (0); 625 } 626 627 static int 628 unpack_header(struct unpack *p, struct dns_header *h) 629 { 630 if (unpack_data(p, h, HFIXEDSZ) == -1) 631 return (-1); 632 633 h->flags = ntohs(h->flags); 634 h->qdcount = ntohs(h->qdcount); 635 h->ancount = ntohs(h->ancount); 636 h->nscount = ntohs(h->nscount); 637 h->arcount = ntohs(h->arcount); 638 639 return (0); 640 } 641 642 static int 643 unpack_query(struct unpack *p, struct dns_query *q) 644 { 645 unpack_dname(p, q->q_dname, sizeof(q->q_dname)); 646 unpack_u16(p, &q->q_type); 647 unpack_u16(p, &q->q_class); 648 649 return (p->err) ? (-1) : (0); 650 } 651 652 static int 653 unpack_rr(struct unpack *p, struct dns_rr *rr) 654 { 655 uint16_t rdlen; 656 size_t save_offset; 657 658 unpack_dname(p, rr->rr_dname, sizeof(rr->rr_dname)); 659 unpack_u16(p, &rr->rr_type); 660 unpack_u16(p, &rr->rr_class); 661 unpack_u32(p, &rr->rr_ttl); 662 unpack_u16(p, &rdlen); 663 664 if (p->err) 665 return (-1); 666 667 if (p->len - p->offset < rdlen) { 668 p->err = "too short"; 669 return (-1); 670 } 671 672 save_offset = p->offset; 673 674 switch (rr->rr_type) { 675 676 case T_CNAME: 677 unpack_dname(p, rr->rr.cname.cname, sizeof(rr->rr.cname.cname)); 678 break; 679 680 case T_MX: 681 unpack_u16(p, &rr->rr.mx.preference); 682 unpack_dname(p, rr->rr.mx.exchange, sizeof(rr->rr.mx.exchange)); 683 break; 684 685 case T_NS: 686 unpack_dname(p, rr->rr.ns.nsname, sizeof(rr->rr.ns.nsname)); 687 break; 688 689 case T_PTR: 690 unpack_dname(p, rr->rr.ptr.ptrname, sizeof(rr->rr.ptr.ptrname)); 691 break; 692 693 case T_SOA: 694 unpack_dname(p, rr->rr.soa.mname, sizeof(rr->rr.soa.mname)); 695 unpack_dname(p, rr->rr.soa.rname, sizeof(rr->rr.soa.rname)); 696 unpack_u32(p, &rr->rr.soa.serial); 697 unpack_u32(p, &rr->rr.soa.refresh); 698 unpack_u32(p, &rr->rr.soa.retry); 699 unpack_u32(p, &rr->rr.soa.expire); 700 unpack_u32(p, &rr->rr.soa.minimum); 701 break; 702 703 case T_A: 704 if (rr->rr_class != C_IN) 705 goto other; 706 unpack_inaddr(p, &rr->rr.in_a.addr); 707 break; 708 709 case T_AAAA: 710 if (rr->rr_class != C_IN) 711 goto other; 712 unpack_in6addr(p, &rr->rr.in_aaaa.addr6); 713 break; 714 default: 715 other: 716 rr->rr.other.rdata = p->buf + p->offset; 717 rr->rr.other.rdlen = rdlen; 718 p->offset += rdlen; 719 } 720 721 if (p->err) 722 return (-1); 723 724 /* make sure that the advertised rdlen is really ok */ 725 if (p->offset - save_offset != rdlen) 726 p->err = "bad dlen"; 727 728 return (p->err) ? (-1) : (0); 729 } 730