1 /** 2 * @file dns/rr.c DNS Resource Records 3 * 4 * Copyright (C) 2010 Creytiv.com 5 */ 6 #include <string.h> 7 #include <re_types.h> 8 #include <re_fmt.h> 9 #include <re_list.h> 10 #include <re_mem.h> 11 #include <re_mbuf.h> 12 #include <re_net.h> 13 #include <re_sa.h> 14 #include <re_dns.h> 15 16 17 static void rr_destructor(void *data) 18 { 19 struct dnsrr *rr = data; 20 21 mem_deref(rr->name); 22 23 switch (rr->type) { 24 25 case DNS_TYPE_NS: 26 mem_deref(rr->rdata.ns.nsdname); 27 break; 28 29 case DNS_TYPE_CNAME: 30 mem_deref(rr->rdata.cname.cname); 31 break; 32 33 case DNS_TYPE_SOA: 34 mem_deref(rr->rdata.soa.mname); 35 mem_deref(rr->rdata.soa.rname); 36 break; 37 38 case DNS_TYPE_PTR: 39 mem_deref(rr->rdata.ptr.ptrdname); 40 break; 41 42 case DNS_TYPE_MX: 43 mem_deref(rr->rdata.mx.exchange); 44 break; 45 46 case DNS_TYPE_SRV: 47 mem_deref(rr->rdata.srv.target); 48 break; 49 50 case DNS_TYPE_NAPTR: 51 mem_deref(rr->rdata.naptr.flags); 52 mem_deref(rr->rdata.naptr.services); 53 mem_deref(rr->rdata.naptr.regexp); 54 mem_deref(rr->rdata.naptr.replace); 55 break; 56 } 57 } 58 59 60 /** 61 * Allocate a new DNS Resource Record (RR) 62 * 63 * @return Newly allocated Resource Record, or NULL if no memory 64 */ 65 struct dnsrr *dns_rr_alloc(void) 66 { 67 return mem_zalloc(sizeof(struct dnsrr), rr_destructor); 68 } 69 70 71 /** 72 * Encode a DNS Resource Record 73 * 74 * @param mb Memory buffer to encode into 75 * @param rr DNS Resource Record 76 * @param ttl_offs TTL Offset 77 * @param ht_dname Domain name hash-table 78 * @param start Start position 79 * 80 * @return 0 if success, otherwise errorcode 81 */ 82 int dns_rr_encode(struct mbuf *mb, const struct dnsrr *rr, int64_t ttl_offs, 83 struct hash *ht_dname, size_t start) 84 { 85 uint32_t ttl; 86 uint16_t len; 87 size_t start_rdata; 88 int err = 0; 89 90 if (!mb || !rr) 91 return EINVAL; 92 93 ttl = (uint32_t)((rr->ttl > ttl_offs) ? (rr->ttl - ttl_offs) : 0); 94 95 err |= dns_dname_encode(mb, rr->name, ht_dname, start, true); 96 err |= mbuf_write_u16(mb, htons(rr->type)); 97 err |= mbuf_write_u16(mb, htons(rr->dnsclass)); 98 err |= mbuf_write_u32(mb, htonl(ttl)); 99 err |= mbuf_write_u16(mb, htons(rr->rdlen)); 100 101 start_rdata = mb->pos; 102 103 switch (rr->type) { 104 105 case DNS_TYPE_A: 106 err |= mbuf_write_u32(mb, htonl(rr->rdata.a.addr)); 107 break; 108 109 case DNS_TYPE_NS: 110 err |= dns_dname_encode(mb, rr->rdata.ns.nsdname, 111 ht_dname, start, true); 112 break; 113 114 case DNS_TYPE_CNAME: 115 err |= dns_dname_encode(mb, rr->rdata.cname.cname, 116 ht_dname, start, true); 117 break; 118 119 case DNS_TYPE_SOA: 120 err |= dns_dname_encode(mb, rr->rdata.soa.mname, 121 ht_dname, start, true); 122 err |= dns_dname_encode(mb, rr->rdata.soa.rname, 123 ht_dname, start, true); 124 err |= mbuf_write_u32(mb, htonl(rr->rdata.soa.serial)); 125 err |= mbuf_write_u32(mb, htonl(rr->rdata.soa.refresh)); 126 err |= mbuf_write_u32(mb, htonl(rr->rdata.soa.retry)); 127 err |= mbuf_write_u32(mb, htonl(rr->rdata.soa.expire)); 128 err |= mbuf_write_u32(mb, htonl(rr->rdata.soa.ttlmin)); 129 break; 130 131 case DNS_TYPE_PTR: 132 err |= dns_dname_encode(mb, rr->rdata.ptr.ptrdname, 133 ht_dname, start, true); 134 break; 135 136 case DNS_TYPE_MX: 137 err |= mbuf_write_u16(mb, htons(rr->rdata.mx.pref)); 138 err |= dns_dname_encode(mb, rr->rdata.mx.exchange, 139 ht_dname, start, true); 140 break; 141 142 case DNS_TYPE_AAAA: 143 err |= mbuf_write_mem(mb, rr->rdata.aaaa.addr, 16); 144 break; 145 146 case DNS_TYPE_SRV: 147 err |= mbuf_write_u16(mb, htons(rr->rdata.srv.pri)); 148 err |= mbuf_write_u16(mb, htons(rr->rdata.srv.weight)); 149 err |= mbuf_write_u16(mb, htons(rr->rdata.srv.port)); 150 err |= dns_dname_encode(mb, rr->rdata.srv.target, 151 ht_dname, start, false); 152 break; 153 154 case DNS_TYPE_NAPTR: 155 err |= mbuf_write_u16(mb, htons(rr->rdata.naptr.order)); 156 err |= mbuf_write_u16(mb, htons(rr->rdata.naptr.pref)); 157 err |= dns_cstr_encode(mb, rr->rdata.naptr.flags); 158 err |= dns_cstr_encode(mb, rr->rdata.naptr.services); 159 err |= dns_cstr_encode(mb, rr->rdata.naptr.regexp); 160 err |= dns_dname_encode(mb, rr->rdata.naptr.replace, 161 ht_dname, start, false); 162 break; 163 164 default: 165 err = EINVAL; 166 break; 167 } 168 169 len = mb->pos - start_rdata; 170 mb->pos = start_rdata - 2; 171 err |= mbuf_write_u16(mb, htons(len)); 172 mb->pos += len; 173 174 return err; 175 } 176 177 178 /** 179 * Decode a DNS Resource Record (RR) from a memory buffer 180 * 181 * @param mb Memory buffer to decode from 182 * @param rr Pointer to allocated Resource Record 183 * @param start Start position 184 * 185 * @return 0 if success, otherwise errorcode 186 */ 187 int dns_rr_decode(struct mbuf *mb, struct dnsrr **rr, size_t start) 188 { 189 int err = 0; 190 struct dnsrr *lrr; 191 192 if (!mb || !rr) 193 return EINVAL; 194 195 lrr = dns_rr_alloc(); 196 if (!lrr) 197 return ENOMEM; 198 199 err = dns_dname_decode(mb, &lrr->name, start); 200 if (err) 201 goto error; 202 203 if (mbuf_get_left(mb) < 10) 204 goto fmerr; 205 206 lrr->type = ntohs(mbuf_read_u16(mb)); 207 lrr->dnsclass = ntohs(mbuf_read_u16(mb)); 208 lrr->ttl = ntohl(mbuf_read_u32(mb)); 209 lrr->rdlen = ntohs(mbuf_read_u16(mb)); 210 211 if (mbuf_get_left(mb) < lrr->rdlen) 212 goto fmerr; 213 214 switch (lrr->type) { 215 216 case DNS_TYPE_A: 217 if (lrr->rdlen != 4) 218 goto fmerr; 219 220 lrr->rdata.a.addr = ntohl(mbuf_read_u32(mb)); 221 break; 222 223 case DNS_TYPE_NS: 224 err = dns_dname_decode(mb, &lrr->rdata.ns.nsdname, start); 225 if (err) 226 goto error; 227 228 break; 229 230 case DNS_TYPE_CNAME: 231 err = dns_dname_decode(mb, &lrr->rdata.cname.cname, start); 232 if (err) 233 goto error; 234 235 break; 236 237 case DNS_TYPE_SOA: 238 err = dns_dname_decode(mb, &lrr->rdata.soa.mname, start); 239 if (err) 240 goto error; 241 242 err = dns_dname_decode(mb, &lrr->rdata.soa.rname, start); 243 if (err) 244 goto error; 245 246 if (mbuf_get_left(mb) < 20) 247 goto fmerr; 248 249 lrr->rdata.soa.serial = ntohl(mbuf_read_u32(mb)); 250 lrr->rdata.soa.refresh = ntohl(mbuf_read_u32(mb)); 251 lrr->rdata.soa.retry = ntohl(mbuf_read_u32(mb)); 252 lrr->rdata.soa.expire = ntohl(mbuf_read_u32(mb)); 253 lrr->rdata.soa.ttlmin = ntohl(mbuf_read_u32(mb)); 254 break; 255 256 case DNS_TYPE_PTR: 257 err = dns_dname_decode(mb, &lrr->rdata.ptr.ptrdname, start); 258 if (err) 259 goto error; 260 261 break; 262 263 case DNS_TYPE_MX: 264 if (mbuf_get_left(mb) < 2) 265 goto fmerr; 266 267 lrr->rdata.mx.pref = ntohs(mbuf_read_u16(mb)); 268 269 err = dns_dname_decode(mb, &lrr->rdata.mx.exchange, start); 270 if (err) 271 goto error; 272 273 break; 274 275 case DNS_TYPE_AAAA: 276 if (lrr->rdlen != 16) 277 goto fmerr; 278 279 err = mbuf_read_mem(mb, lrr->rdata.aaaa.addr, 16); 280 if (err) 281 goto error; 282 break; 283 284 case DNS_TYPE_SRV: 285 if (mbuf_get_left(mb) < 6) 286 goto fmerr; 287 288 lrr->rdata.srv.pri = ntohs(mbuf_read_u16(mb)); 289 lrr->rdata.srv.weight = ntohs(mbuf_read_u16(mb)); 290 lrr->rdata.srv.port = ntohs(mbuf_read_u16(mb)); 291 292 err = dns_dname_decode(mb, &lrr->rdata.srv.target, start); 293 if (err) 294 goto error; 295 296 break; 297 298 case DNS_TYPE_NAPTR: 299 if (mbuf_get_left(mb) < 4) 300 goto fmerr; 301 302 lrr->rdata.naptr.order = ntohs(mbuf_read_u16(mb)); 303 lrr->rdata.naptr.pref = ntohs(mbuf_read_u16(mb)); 304 305 err = dns_cstr_decode(mb, &lrr->rdata.naptr.flags); 306 if (err) 307 goto error; 308 309 err = dns_cstr_decode(mb, &lrr->rdata.naptr.services); 310 if (err) 311 goto error; 312 313 err = dns_cstr_decode(mb, &lrr->rdata.naptr.regexp); 314 if (err) 315 goto error; 316 317 err = dns_dname_decode(mb, &lrr->rdata.naptr.replace, start); 318 if (err) 319 goto error; 320 321 break; 322 323 default: 324 mb->pos += lrr->rdlen; 325 break; 326 } 327 328 *rr = lrr; 329 330 return 0; 331 332 fmerr: 333 err = EINVAL; 334 error: 335 mem_deref(lrr); 336 337 return err; 338 } 339 340 341 /** 342 * Compare two DNS Resource Records 343 * 344 * @param rr1 First Resource Record 345 * @param rr2 Second Resource Record 346 * @param rdata If true, also compares Resource Record data 347 * 348 * @return True if match, false if not match 349 */ 350 bool dns_rr_cmp(const struct dnsrr *rr1, const struct dnsrr *rr2, bool rdata) 351 { 352 if (!rr1 || !rr2) 353 return false; 354 355 if (rr1 == rr2) 356 return true; 357 358 if (rr1->type != rr2->type) 359 return false; 360 361 if (rr1->dnsclass != rr2->dnsclass) 362 return false; 363 364 if (str_casecmp(rr1->name, rr2->name)) 365 return false; 366 367 if (!rdata) 368 return true; 369 370 switch (rr1->type) { 371 372 case DNS_TYPE_A: 373 if (rr1->rdata.a.addr != rr2->rdata.a.addr) 374 return false; 375 376 break; 377 378 case DNS_TYPE_NS: 379 if (str_casecmp(rr1->rdata.ns.nsdname, rr2->rdata.ns.nsdname)) 380 return false; 381 382 break; 383 384 case DNS_TYPE_CNAME: 385 if (str_casecmp(rr1->rdata.cname.cname, 386 rr2->rdata.cname.cname)) 387 return false; 388 389 break; 390 391 case DNS_TYPE_SOA: 392 if (str_casecmp(rr1->rdata.soa.mname, rr2->rdata.soa.mname)) 393 return false; 394 395 if (str_casecmp(rr1->rdata.soa.rname, rr2->rdata.soa.rname)) 396 return false; 397 398 if (rr1->rdata.soa.serial != rr2->rdata.soa.serial) 399 return false; 400 401 if (rr1->rdata.soa.refresh != rr2->rdata.soa.refresh) 402 return false; 403 404 if (rr1->rdata.soa.retry != rr2->rdata.soa.retry) 405 return false; 406 407 if (rr1->rdata.soa.expire != rr2->rdata.soa.expire) 408 return false; 409 410 if (rr1->rdata.soa.ttlmin != rr2->rdata.soa.ttlmin) 411 return false; 412 413 break; 414 415 case DNS_TYPE_PTR: 416 if (str_casecmp(rr1->rdata.ptr.ptrdname, 417 rr2->rdata.ptr.ptrdname)) 418 return false; 419 420 break; 421 422 case DNS_TYPE_MX: 423 if (rr1->rdata.mx.pref != rr2->rdata.mx.pref) 424 return false; 425 426 if (str_casecmp(rr1->rdata.mx.exchange, 427 rr2->rdata.mx.exchange)) 428 return false; 429 430 break; 431 432 case DNS_TYPE_AAAA: 433 if (memcmp(rr1->rdata.aaaa.addr, rr2->rdata.aaaa.addr, 16)) 434 return false; 435 436 break; 437 438 case DNS_TYPE_SRV: 439 if (rr1->rdata.srv.pri != rr2->rdata.srv.pri) 440 return false; 441 442 if (rr1->rdata.srv.weight != rr2->rdata.srv.weight) 443 return false; 444 445 if (rr1->rdata.srv.port != rr2->rdata.srv.port) 446 return false; 447 448 if (str_casecmp(rr1->rdata.srv.target, rr2->rdata.srv.target)) 449 return false; 450 451 break; 452 453 case DNS_TYPE_NAPTR: 454 if (rr1->rdata.naptr.order != rr2->rdata.naptr.order) 455 return false; 456 457 if (rr1->rdata.naptr.pref != rr2->rdata.naptr.pref) 458 return false; 459 460 /* todo check case sensitiveness */ 461 if (str_casecmp(rr1->rdata.naptr.flags, 462 rr2->rdata.naptr.flags)) 463 return false; 464 465 /* todo check case sensitiveness */ 466 if (str_casecmp(rr1->rdata.naptr.services, 467 rr2->rdata.naptr.services)) 468 return false; 469 470 /* todo check case sensitiveness */ 471 if (str_casecmp(rr1->rdata.naptr.regexp, 472 rr2->rdata.naptr.regexp)) 473 return false; 474 475 /* todo check case sensitiveness */ 476 if (str_casecmp(rr1->rdata.naptr.replace, 477 rr2->rdata.naptr.replace)) 478 return false; 479 480 break; 481 482 default: 483 return false; 484 } 485 486 return true; 487 } 488 489 490 /** 491 * Get the DNS Resource Record (RR) name 492 * 493 * @param type DNS Resource Record type 494 * 495 * @return DNS Resource Record name 496 */ 497 const char *dns_rr_typename(uint16_t type) 498 { 499 switch (type) { 500 501 case DNS_TYPE_A: return "A"; 502 case DNS_TYPE_NS: return "NS"; 503 case DNS_TYPE_CNAME: return "CNAME"; 504 case DNS_TYPE_SOA: return "SOA"; 505 case DNS_TYPE_PTR: return "PTR"; 506 case DNS_TYPE_MX: return "MX"; 507 case DNS_TYPE_AAAA: return "AAAA"; 508 case DNS_TYPE_SRV: return "SRV"; 509 case DNS_TYPE_NAPTR: return "NAPTR"; 510 case DNS_QTYPE_IXFR: return "IXFR"; 511 case DNS_QTYPE_AXFR: return "AXFR"; 512 case DNS_QTYPE_ANY: return "ANY"; 513 default: return "??"; 514 } 515 } 516 517 518 /** 519 * Get the DNS Resource Record (RR) class name 520 * 521 * @param dnsclass DNS Class 522 * 523 * @return DNS Class name 524 */ 525 const char *dns_rr_classname(uint16_t dnsclass) 526 { 527 switch (dnsclass) { 528 529 case DNS_CLASS_IN: return "IN"; 530 case DNS_QCLASS_ANY: return "ANY"; 531 default: return "??"; 532 } 533 } 534 535 536 /** 537 * Print a DNS Resource Record 538 * 539 * @param pf Print function 540 * @param rr DNS Resource Record 541 * 542 * @return 0 if success, otherwise errorcode 543 */ 544 int dns_rr_print(struct re_printf *pf, const struct dnsrr *rr) 545 { 546 static const size_t w = 24; 547 struct sa sa; 548 size_t n, l; 549 int err; 550 551 if (!pf || !rr) 552 return EINVAL; 553 554 l = str_len(rr->name); 555 n = (w > l) ? w - l : 0; 556 557 err = re_hprintf(pf, "%s.", rr->name); 558 while (n--) 559 err |= pf->vph(" ", 1, pf->arg); 560 561 err |= re_hprintf(pf, " %10lld %-4s %-7s ", 562 rr->ttl, 563 dns_rr_classname(rr->dnsclass), 564 dns_rr_typename(rr->type)); 565 566 switch (rr->type) { 567 568 case DNS_TYPE_A: 569 sa_set_in(&sa, rr->rdata.a.addr, 0); 570 err |= re_hprintf(pf, "%j", &sa); 571 break; 572 573 case DNS_TYPE_NS: 574 err |= re_hprintf(pf, "%s.", rr->rdata.ns.nsdname); 575 break; 576 577 case DNS_TYPE_CNAME: 578 err |= re_hprintf(pf, "%s.", rr->rdata.cname.cname); 579 break; 580 581 case DNS_TYPE_SOA: 582 err |= re_hprintf(pf, "%s. %s. %u %u %u %u %u", 583 rr->rdata.soa.mname, 584 rr->rdata.soa.rname, 585 rr->rdata.soa.serial, 586 rr->rdata.soa.refresh, 587 rr->rdata.soa.retry, 588 rr->rdata.soa.expire, 589 rr->rdata.soa.ttlmin); 590 break; 591 592 case DNS_TYPE_PTR: 593 err |= re_hprintf(pf, "%s.", rr->rdata.ptr.ptrdname); 594 break; 595 596 case DNS_TYPE_MX: 597 err |= re_hprintf(pf, "%3u %s.", rr->rdata.mx.pref, 598 rr->rdata.mx.exchange); 599 break; 600 601 case DNS_TYPE_AAAA: 602 sa_set_in6(&sa, rr->rdata.aaaa.addr, 0); 603 err |= re_hprintf(pf, "%j", &sa); 604 break; 605 606 case DNS_TYPE_SRV: 607 err |= re_hprintf(pf, "%3u %3u %u %s.", 608 rr->rdata.srv.pri, 609 rr->rdata.srv.weight, 610 rr->rdata.srv.port, 611 rr->rdata.srv.target); 612 break; 613 614 case DNS_TYPE_NAPTR: 615 err |= re_hprintf(pf, "%3u %3u \"%s\" \"%s\" \"%s\" %s.", 616 rr->rdata.naptr.order, 617 rr->rdata.naptr.pref, 618 rr->rdata.naptr.flags, 619 rr->rdata.naptr.services, 620 rr->rdata.naptr.regexp, 621 rr->rdata.naptr.replace); 622 break; 623 624 default: 625 err |= re_hprintf(pf, "?"); 626 break; 627 } 628 629 return err; 630 } 631