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