1 /*** 2 This file is part of avahi. 3 4 avahi is free software; you can redistribute it and/or modify it 5 under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 2.1 of the 7 License, or (at your option) any later version. 8 9 avahi is distributed in the hope that it will be useful, but WITHOUT 10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 11 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 12 Public License for more details. 13 14 You should have received a copy of the GNU Lesser General Public 15 License along with avahi; if not, write to the Free Software 16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 17 USA. 18 ***/ 19 20 #ifdef HAVE_CONFIG_H 21 #include <config.h> 22 #endif 23 24 #include <stdlib.h> 25 #include <string.h> 26 #include <stdio.h> 27 #include <assert.h> 28 29 #include <sys/types.h> 30 #include <netinet/in.h> 31 32 #include <avahi-common/defs.h> 33 #include <avahi-common/domain.h> 34 #include "avahi-common/avahi-malloc.h" 35 36 #include "dns.h" 37 #include "log.h" 38 39 AvahiDnsPacket* avahi_dns_packet_new(unsigned mtu) { 40 AvahiDnsPacket *p; 41 size_t max_size; 42 43 if (mtu <= 0) 44 max_size = AVAHI_DNS_PACKET_SIZE_MAX; 45 else if (mtu >= AVAHI_DNS_PACKET_EXTRA_SIZE) 46 max_size = mtu - AVAHI_DNS_PACKET_EXTRA_SIZE; 47 else 48 max_size = 0; 49 50 if (max_size < AVAHI_DNS_PACKET_HEADER_SIZE) 51 max_size = AVAHI_DNS_PACKET_HEADER_SIZE; 52 53 if (!(p = avahi_malloc(sizeof(AvahiDnsPacket) + max_size))) 54 return p; 55 56 p->size = p->rindex = AVAHI_DNS_PACKET_HEADER_SIZE; 57 p->max_size = max_size; 58 p->name_table = NULL; 59 p->data = NULL; 60 61 memset(AVAHI_DNS_PACKET_DATA(p), 0, p->size); 62 return p; 63 } 64 65 AvahiDnsPacket* avahi_dns_packet_new_query(unsigned mtu) { 66 AvahiDnsPacket *p; 67 68 if (!(p = avahi_dns_packet_new(mtu))) 69 return NULL; 70 71 avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); 72 return p; 73 } 74 75 AvahiDnsPacket* avahi_dns_packet_new_response(unsigned mtu, int aa) { 76 AvahiDnsPacket *p; 77 78 if (!(p = avahi_dns_packet_new(mtu))) 79 return NULL; 80 81 avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(1, 0, aa, 0, 0, 0, 0, 0, 0, 0)); 82 return p; 83 } 84 85 AvahiDnsPacket* avahi_dns_packet_new_reply(AvahiDnsPacket* p, unsigned mtu, int copy_queries, int aa) { 86 AvahiDnsPacket *r; 87 assert(p); 88 89 if (!(r = avahi_dns_packet_new_response(mtu, aa))) 90 return NULL; 91 92 if (copy_queries) { 93 unsigned saved_rindex; 94 uint32_t n; 95 96 saved_rindex = p->rindex; 97 p->rindex = AVAHI_DNS_PACKET_HEADER_SIZE; 98 99 for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT); n > 0; n--) { 100 AvahiKey *k; 101 int unicast_response; 102 103 if ((k = avahi_dns_packet_consume_key(p, &unicast_response))) { 104 avahi_dns_packet_append_key(r, k, unicast_response); 105 avahi_key_unref(k); 106 } 107 } 108 109 p->rindex = saved_rindex; 110 111 avahi_dns_packet_set_field(r, AVAHI_DNS_FIELD_QDCOUNT, avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT)); 112 } 113 114 avahi_dns_packet_set_field(r, AVAHI_DNS_FIELD_ID, avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ID)); 115 116 avahi_dns_packet_set_field(r, AVAHI_DNS_FIELD_FLAGS, 117 (avahi_dns_packet_get_field(r, AVAHI_DNS_FIELD_FLAGS) & ~AVAHI_DNS_FLAG_OPCODE) | 118 (avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS) & AVAHI_DNS_FLAG_OPCODE)); 119 120 return r; 121 } 122 123 124 void avahi_dns_packet_free(AvahiDnsPacket *p) { 125 assert(p); 126 127 if (p->name_table) 128 avahi_hashmap_free(p->name_table); 129 130 avahi_free(p); 131 } 132 133 void avahi_dns_packet_set_field(AvahiDnsPacket *p, unsigned idx, uint16_t v) { 134 assert(p); 135 assert(idx < AVAHI_DNS_PACKET_HEADER_SIZE); 136 137 ((uint16_t*) AVAHI_DNS_PACKET_DATA(p))[idx] = htons(v); 138 } 139 140 uint16_t avahi_dns_packet_get_field(AvahiDnsPacket *p, unsigned idx) { 141 assert(p); 142 assert(idx < AVAHI_DNS_PACKET_HEADER_SIZE); 143 144 return ntohs(((uint16_t*) AVAHI_DNS_PACKET_DATA(p))[idx]); 145 } 146 147 void avahi_dns_packet_inc_field(AvahiDnsPacket *p, unsigned idx) { 148 assert(p); 149 assert(idx < AVAHI_DNS_PACKET_HEADER_SIZE); 150 151 avahi_dns_packet_set_field(p, idx, avahi_dns_packet_get_field(p, idx) + 1); 152 } 153 154 155 static void name_table_cleanup(void *key, void *value, void *user_data) { 156 AvahiDnsPacket *p = user_data; 157 158 if ((uint8_t*) value >= AVAHI_DNS_PACKET_DATA(p) + p->size) 159 avahi_hashmap_remove(p->name_table, key); 160 } 161 162 void avahi_dns_packet_cleanup_name_table(AvahiDnsPacket *p) { 163 if (p->name_table) 164 avahi_hashmap_foreach(p->name_table, name_table_cleanup, p); 165 } 166 167 uint8_t* avahi_dns_packet_append_name(AvahiDnsPacket *p, const char *name) { 168 uint8_t *d, *saved_ptr = NULL; 169 size_t saved_size; 170 171 assert(p); 172 assert(name); 173 174 saved_size = p->size; 175 saved_ptr = avahi_dns_packet_extend(p, 0); 176 177 while (*name) { 178 uint8_t* prev; 179 const char *pname; 180 char label[64], *u; 181 182 /* Check whether we can compress this name. */ 183 184 if (p->name_table && (prev = avahi_hashmap_lookup(p->name_table, name))) { 185 unsigned idx; 186 187 assert(prev >= AVAHI_DNS_PACKET_DATA(p)); 188 idx = (unsigned) (prev - AVAHI_DNS_PACKET_DATA(p)); 189 190 assert(idx < p->size); 191 192 if (idx < 0x4000) { 193 uint8_t *t; 194 if (!(t = (uint8_t*) avahi_dns_packet_extend(p, sizeof(uint16_t)))) 195 return NULL; 196 197 t[0] = (uint8_t) ((0xC000 | idx) >> 8); 198 t[1] = (uint8_t) idx; 199 return saved_ptr; 200 } 201 } 202 203 pname = name; 204 205 if (!(avahi_unescape_label(&name, label, sizeof(label)))) 206 goto fail; 207 208 if (!(d = avahi_dns_packet_append_string(p, label))) 209 goto fail; 210 211 if (!p->name_table) 212 /* This works only for normalized domain names */ 213 p->name_table = avahi_hashmap_new(avahi_string_hash, avahi_string_equal, avahi_free, NULL); 214 215 if (!(u = avahi_strdup(pname))) 216 avahi_log_error("avahi_strdup() failed."); 217 else 218 avahi_hashmap_insert(p->name_table, u, d); 219 } 220 221 if (!(d = avahi_dns_packet_extend(p, 1))) 222 goto fail; 223 224 *d = 0; 225 226 return saved_ptr; 227 228 fail: 229 p->size = saved_size; 230 avahi_dns_packet_cleanup_name_table(p); 231 232 return NULL; 233 } 234 235 uint8_t* avahi_dns_packet_append_uint16(AvahiDnsPacket *p, uint16_t v) { 236 uint8_t *d; 237 assert(p); 238 239 if (!(d = avahi_dns_packet_extend(p, sizeof(uint16_t)))) 240 return NULL; 241 242 d[0] = (uint8_t) (v >> 8); 243 d[1] = (uint8_t) v; 244 return d; 245 } 246 247 uint8_t *avahi_dns_packet_append_uint32(AvahiDnsPacket *p, uint32_t v) { 248 uint8_t *d; 249 assert(p); 250 251 if (!(d = avahi_dns_packet_extend(p, sizeof(uint32_t)))) 252 return NULL; 253 254 d[0] = (uint8_t) (v >> 24); 255 d[1] = (uint8_t) (v >> 16); 256 d[2] = (uint8_t) (v >> 8); 257 d[3] = (uint8_t) v; 258 259 return d; 260 } 261 262 uint8_t *avahi_dns_packet_append_bytes(AvahiDnsPacket *p, const void *b, size_t l) { 263 uint8_t* d; 264 265 assert(p); 266 assert(b); 267 assert(l); 268 269 if (!(d = avahi_dns_packet_extend(p, l))) 270 return NULL; 271 272 memcpy(d, b, l); 273 return d; 274 } 275 276 uint8_t* avahi_dns_packet_append_string(AvahiDnsPacket *p, const char *s) { 277 uint8_t* d; 278 size_t k; 279 280 assert(p); 281 assert(s); 282 283 if ((k = strlen(s)) >= 255) 284 k = 255; 285 286 if (!(d = avahi_dns_packet_extend(p, k+1))) 287 return NULL; 288 289 *d = (uint8_t) k; 290 memcpy(d+1, s, k); 291 292 return d; 293 } 294 295 uint8_t *avahi_dns_packet_extend(AvahiDnsPacket *p, size_t l) { 296 uint8_t *d; 297 298 assert(p); 299 300 if (p->size+l > p->max_size) 301 return NULL; 302 303 d = AVAHI_DNS_PACKET_DATA(p) + p->size; 304 p->size += l; 305 306 return d; 307 } 308 309 int avahi_dns_packet_check_valid(AvahiDnsPacket *p) { 310 uint16_t flags; 311 assert(p); 312 313 if (p->size < AVAHI_DNS_PACKET_HEADER_SIZE) 314 return -1; 315 316 flags = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS); 317 318 if (flags & AVAHI_DNS_FLAG_OPCODE) 319 return -1; 320 321 return 0; 322 } 323 324 int avahi_dns_packet_check_valid_multicast(AvahiDnsPacket *p) { 325 uint16_t flags; 326 assert(p); 327 328 if (avahi_dns_packet_check_valid(p) < 0) 329 return -1; 330 331 flags = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS); 332 333 if (flags & AVAHI_DNS_FLAG_RCODE) 334 return -1; 335 336 return 0; 337 } 338 339 int avahi_dns_packet_is_query(AvahiDnsPacket *p) { 340 assert(p); 341 342 return !(avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS) & AVAHI_DNS_FLAG_QR); 343 } 344 345 static int consume_labels(AvahiDnsPacket *p, unsigned idx, char *ret_name, size_t l) { 346 int ret = 0; 347 int compressed = 0; 348 int first_label = 1; 349 unsigned label_ptr; 350 int i; 351 assert(p && ret_name && l); 352 353 for (i = 0; i < AVAHI_DNS_LABELS_MAX; i++) { 354 uint8_t n; 355 356 if (idx+1 > p->size) 357 return -1; 358 359 n = AVAHI_DNS_PACKET_DATA(p)[idx]; 360 361 if (!n) { 362 idx++; 363 if (!compressed) 364 ret++; 365 366 if (l < 1) 367 return -1; 368 *ret_name = 0; 369 370 return ret; 371 372 } else if (n <= 63) { 373 /* Uncompressed label */ 374 idx++; 375 if (!compressed) 376 ret++; 377 378 if (idx + n > p->size) 379 return -1; 380 381 if ((size_t) n + 1 > l) 382 return -1; 383 384 if (!first_label) { 385 *(ret_name++) = '.'; 386 l--; 387 } else 388 first_label = 0; 389 390 if (!(avahi_escape_label((char*) AVAHI_DNS_PACKET_DATA(p) + idx, n, &ret_name, &l))) 391 return -1; 392 393 idx += n; 394 395 if (!compressed) 396 ret += n; 397 } else if ((n & 0xC0) == 0xC0) { 398 /* Compressed label */ 399 400 if (idx+2 > p->size) 401 return -1; 402 403 label_ptr = ((unsigned) (AVAHI_DNS_PACKET_DATA(p)[idx] & ~0xC0)) << 8 | AVAHI_DNS_PACKET_DATA(p)[idx+1]; 404 405 if ((label_ptr < AVAHI_DNS_PACKET_HEADER_SIZE) || (label_ptr >= idx)) 406 return -1; 407 408 idx = label_ptr; 409 410 if (!compressed) 411 ret += 2; 412 413 compressed = 1; 414 } else 415 return -1; 416 } 417 418 return -1; 419 } 420 421 int avahi_dns_packet_consume_name(AvahiDnsPacket *p, char *ret_name, size_t l) { 422 int r; 423 424 if ((r = consume_labels(p, p->rindex, ret_name, l)) < 0) 425 return -1; 426 427 p->rindex += r; 428 return 0; 429 } 430 431 int avahi_dns_packet_consume_uint16(AvahiDnsPacket *p, uint16_t *ret_v) { 432 uint8_t *d; 433 434 assert(p); 435 assert(ret_v); 436 437 if (p->rindex + sizeof(uint16_t) > p->size) 438 return -1; 439 440 d = (uint8_t*) (AVAHI_DNS_PACKET_DATA(p) + p->rindex); 441 *ret_v = (d[0] << 8) | d[1]; 442 p->rindex += sizeof(uint16_t); 443 444 return 0; 445 } 446 447 int avahi_dns_packet_consume_uint32(AvahiDnsPacket *p, uint32_t *ret_v) { 448 uint8_t* d; 449 450 assert(p); 451 assert(ret_v); 452 453 if (p->rindex + sizeof(uint32_t) > p->size) 454 return -1; 455 456 d = (uint8_t*) (AVAHI_DNS_PACKET_DATA(p) + p->rindex); 457 *ret_v = (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3]; 458 p->rindex += sizeof(uint32_t); 459 460 return 0; 461 } 462 463 int avahi_dns_packet_consume_bytes(AvahiDnsPacket *p, void * ret_data, size_t l) { 464 assert(p); 465 assert(ret_data); 466 assert(l > 0); 467 468 if (p->rindex + l > p->size) 469 return -1; 470 471 memcpy(ret_data, AVAHI_DNS_PACKET_DATA(p) + p->rindex, l); 472 p->rindex += l; 473 474 return 0; 475 } 476 477 int avahi_dns_packet_consume_string(AvahiDnsPacket *p, char *ret_string, size_t l) { 478 size_t k; 479 480 assert(p); 481 assert(ret_string); 482 assert(l > 0); 483 484 if (p->rindex >= p->size) 485 return -1; 486 487 k = AVAHI_DNS_PACKET_DATA(p)[p->rindex]; 488 489 if (p->rindex+1+k > p->size) 490 return -1; 491 492 if (l > k+1) 493 l = k+1; 494 495 memcpy(ret_string, AVAHI_DNS_PACKET_DATA(p)+p->rindex+1, l-1); 496 ret_string[l-1] = 0; 497 498 p->rindex += 1+k; 499 500 return 0; 501 } 502 503 const void* avahi_dns_packet_get_rptr(AvahiDnsPacket *p) { 504 assert(p); 505 506 if (p->rindex > p->size) 507 return NULL; 508 509 return AVAHI_DNS_PACKET_DATA(p) + p->rindex; 510 } 511 512 int avahi_dns_packet_skip(AvahiDnsPacket *p, size_t length) { 513 assert(p); 514 515 if (p->rindex + length > p->size) 516 return -1; 517 518 p->rindex += length; 519 return 0; 520 } 521 522 static int parse_rdata(AvahiDnsPacket *p, AvahiRecord *r, uint16_t rdlength) { 523 char buf[AVAHI_DOMAIN_NAME_MAX]; 524 const void* start; 525 526 assert(p); 527 assert(r); 528 529 start = avahi_dns_packet_get_rptr(p); 530 531 switch (r->key->type) { 532 case AVAHI_DNS_TYPE_PTR: 533 case AVAHI_DNS_TYPE_CNAME: 534 case AVAHI_DNS_TYPE_NS: 535 536 if (avahi_dns_packet_consume_name(p, buf, sizeof(buf)) < 0) 537 return -1; 538 539 r->data.ptr.name = avahi_strdup(buf); 540 break; 541 542 543 case AVAHI_DNS_TYPE_SRV: 544 545 if (avahi_dns_packet_consume_uint16(p, &r->data.srv.priority) < 0 || 546 avahi_dns_packet_consume_uint16(p, &r->data.srv.weight) < 0 || 547 avahi_dns_packet_consume_uint16(p, &r->data.srv.port) < 0 || 548 avahi_dns_packet_consume_name(p, buf, sizeof(buf)) < 0) 549 return -1; 550 551 r->data.srv.name = avahi_strdup(buf); 552 break; 553 554 case AVAHI_DNS_TYPE_HINFO: 555 556 if (avahi_dns_packet_consume_string(p, buf, sizeof(buf)) < 0) 557 return -1; 558 559 r->data.hinfo.cpu = avahi_strdup(buf); 560 561 if (avahi_dns_packet_consume_string(p, buf, sizeof(buf)) < 0) 562 return -1; 563 564 r->data.hinfo.os = avahi_strdup(buf); 565 break; 566 567 case AVAHI_DNS_TYPE_TXT: 568 569 if (rdlength > 0) { 570 if (avahi_string_list_parse(avahi_dns_packet_get_rptr(p), rdlength, &r->data.txt.string_list) < 0) 571 return -1; 572 573 if (avahi_dns_packet_skip(p, rdlength) < 0) 574 return -1; 575 } else 576 r->data.txt.string_list = NULL; 577 578 break; 579 580 case AVAHI_DNS_TYPE_A: 581 582 /* avahi_log_debug("A"); */ 583 584 if (avahi_dns_packet_consume_bytes(p, &r->data.a.address, sizeof(AvahiIPv4Address)) < 0) 585 return -1; 586 587 break; 588 589 case AVAHI_DNS_TYPE_AAAA: 590 591 /* avahi_log_debug("aaaa"); */ 592 593 if (avahi_dns_packet_consume_bytes(p, &r->data.aaaa.address, sizeof(AvahiIPv6Address)) < 0) 594 return -1; 595 596 break; 597 598 default: 599 600 /* avahi_log_debug("generic"); */ 601 602 if (rdlength > 0) { 603 604 r->data.generic.data = avahi_memdup(avahi_dns_packet_get_rptr(p), rdlength); 605 r->data.generic.size = rdlength; 606 607 if (avahi_dns_packet_skip(p, rdlength) < 0) 608 return -1; 609 } 610 611 break; 612 } 613 614 /* Check if we read enough data */ 615 if ((const uint8_t*) avahi_dns_packet_get_rptr(p) - (const uint8_t*) start != rdlength) 616 return -1; 617 618 return 0; 619 } 620 621 AvahiRecord* avahi_dns_packet_consume_record(AvahiDnsPacket *p, int *ret_cache_flush) { 622 char name[AVAHI_DOMAIN_NAME_MAX]; 623 uint16_t type, class; 624 uint32_t ttl; 625 uint16_t rdlength; 626 AvahiRecord *r = NULL; 627 628 assert(p); 629 630 if (avahi_dns_packet_consume_name(p, name, sizeof(name)) < 0 || 631 avahi_dns_packet_consume_uint16(p, &type) < 0 || 632 avahi_dns_packet_consume_uint16(p, &class) < 0 || 633 avahi_dns_packet_consume_uint32(p, &ttl) < 0 || 634 avahi_dns_packet_consume_uint16(p, &rdlength) < 0 || 635 p->rindex + rdlength > p->size) 636 goto fail; 637 638 if (ret_cache_flush) 639 *ret_cache_flush = !!(class & AVAHI_DNS_CACHE_FLUSH); 640 class &= ~AVAHI_DNS_CACHE_FLUSH; 641 642 if (!(r = avahi_record_new_full(name, class, type, ttl))) 643 goto fail; 644 645 if (parse_rdata(p, r, rdlength) < 0) 646 goto fail; 647 648 if (!avahi_record_is_valid(r)) 649 goto fail; 650 651 return r; 652 653 fail: 654 if (r) 655 avahi_record_unref(r); 656 657 return NULL; 658 } 659 660 AvahiKey* avahi_dns_packet_consume_key(AvahiDnsPacket *p, int *ret_unicast_response) { 661 char name[256]; 662 uint16_t type, class; 663 AvahiKey *k; 664 665 assert(p); 666 667 if (avahi_dns_packet_consume_name(p, name, sizeof(name)) < 0 || 668 avahi_dns_packet_consume_uint16(p, &type) < 0 || 669 avahi_dns_packet_consume_uint16(p, &class) < 0) 670 return NULL; 671 672 if (ret_unicast_response) 673 *ret_unicast_response = !!(class & AVAHI_DNS_UNICAST_RESPONSE); 674 675 class &= ~AVAHI_DNS_UNICAST_RESPONSE; 676 677 if (!(k = avahi_key_new(name, class, type))) 678 return NULL; 679 680 if (!avahi_key_is_valid(k)) { 681 avahi_key_unref(k); 682 return NULL; 683 } 684 685 return k; 686 } 687 688 uint8_t* avahi_dns_packet_append_key(AvahiDnsPacket *p, AvahiKey *k, int unicast_response) { 689 uint8_t *t; 690 size_t size; 691 692 assert(p); 693 assert(k); 694 695 size = p->size; 696 697 if (!(t = avahi_dns_packet_append_name(p, k->name)) || 698 !avahi_dns_packet_append_uint16(p, k->type) || 699 !avahi_dns_packet_append_uint16(p, k->clazz | (unicast_response ? AVAHI_DNS_UNICAST_RESPONSE : 0))) { 700 p->size = size; 701 avahi_dns_packet_cleanup_name_table(p); 702 703 return NULL; 704 } 705 706 return t; 707 } 708 709 static int append_rdata(AvahiDnsPacket *p, AvahiRecord *r) { 710 assert(p); 711 assert(r); 712 713 switch (r->key->type) { 714 715 case AVAHI_DNS_TYPE_PTR: 716 case AVAHI_DNS_TYPE_CNAME: 717 case AVAHI_DNS_TYPE_NS: 718 719 if (!(avahi_dns_packet_append_name(p, r->data.ptr.name))) 720 return -1; 721 722 break; 723 724 case AVAHI_DNS_TYPE_SRV: 725 726 if (!avahi_dns_packet_append_uint16(p, r->data.srv.priority) || 727 !avahi_dns_packet_append_uint16(p, r->data.srv.weight) || 728 !avahi_dns_packet_append_uint16(p, r->data.srv.port) || 729 !avahi_dns_packet_append_name(p, r->data.srv.name)) 730 return -1; 731 732 break; 733 734 case AVAHI_DNS_TYPE_HINFO: 735 if (!avahi_dns_packet_append_string(p, r->data.hinfo.cpu) || 736 !avahi_dns_packet_append_string(p, r->data.hinfo.os)) 737 return -1; 738 739 break; 740 741 case AVAHI_DNS_TYPE_TXT: { 742 743 uint8_t *data; 744 size_t n; 745 746 n = avahi_string_list_serialize(r->data.txt.string_list, NULL, 0); 747 748 if (!(data = avahi_dns_packet_extend(p, n))) 749 return -1; 750 751 avahi_string_list_serialize(r->data.txt.string_list, data, n); 752 break; 753 } 754 755 756 case AVAHI_DNS_TYPE_A: 757 758 if (!avahi_dns_packet_append_bytes(p, &r->data.a.address, sizeof(r->data.a.address))) 759 return -1; 760 761 break; 762 763 case AVAHI_DNS_TYPE_AAAA: 764 765 if (!avahi_dns_packet_append_bytes(p, &r->data.aaaa.address, sizeof(r->data.aaaa.address))) 766 return -1; 767 768 break; 769 770 default: 771 772 if (r->data.generic.size) 773 if (!avahi_dns_packet_append_bytes(p, r->data.generic.data, r->data.generic.size)) 774 return -1; 775 776 break; 777 } 778 779 return 0; 780 } 781 782 783 uint8_t* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, int cache_flush, unsigned max_ttl) { 784 uint8_t *t, *l, *start; 785 size_t size; 786 787 assert(p); 788 assert(r); 789 790 size = p->size; 791 792 if (!(t = avahi_dns_packet_append_name(p, r->key->name)) || 793 !avahi_dns_packet_append_uint16(p, r->key->type) || 794 !avahi_dns_packet_append_uint16(p, cache_flush ? (r->key->clazz | AVAHI_DNS_CACHE_FLUSH) : (r->key->clazz &~ AVAHI_DNS_CACHE_FLUSH)) || 795 !avahi_dns_packet_append_uint32(p, (max_ttl && r->ttl > max_ttl) ? max_ttl : r->ttl) || 796 !(l = avahi_dns_packet_append_uint16(p, 0))) 797 goto fail; 798 799 start = avahi_dns_packet_extend(p, 0); 800 801 if (append_rdata(p, r) < 0) 802 goto fail; 803 804 size = avahi_dns_packet_extend(p, 0) - start; 805 assert(size <= AVAHI_DNS_RDATA_MAX); 806 807 /* avahi_log_debug("appended %u", size); */ 808 809 l[0] = (uint8_t) ((uint16_t) size >> 8); 810 l[1] = (uint8_t) ((uint16_t) size); 811 812 return t; 813 814 815 fail: 816 p->size = size; 817 avahi_dns_packet_cleanup_name_table(p); 818 819 return NULL; 820 } 821 822 int avahi_dns_packet_is_empty(AvahiDnsPacket *p) { 823 assert(p); 824 825 return p->size <= AVAHI_DNS_PACKET_HEADER_SIZE; 826 } 827 828 size_t avahi_dns_packet_space(AvahiDnsPacket *p) { 829 assert(p); 830 831 assert(p->size <= p->max_size); 832 833 return p->max_size - p->size; 834 } 835 836 int avahi_rdata_parse(AvahiRecord *record, const void* rdata, size_t size) { 837 int ret; 838 AvahiDnsPacket p; 839 840 assert(record); 841 assert(rdata); 842 843 p.data = (void*) rdata; 844 p.max_size = p.size = size; 845 p.rindex = 0; 846 p.name_table = NULL; 847 848 ret = parse_rdata(&p, record, size); 849 850 assert(!p.name_table); 851 852 return ret; 853 } 854 855 size_t avahi_rdata_serialize(AvahiRecord *record, void *rdata, size_t max_size) { 856 int ret; 857 AvahiDnsPacket p; 858 859 assert(record); 860 assert(rdata); 861 assert(max_size > 0); 862 863 p.data = (void*) rdata; 864 p.max_size = max_size; 865 p.size = p.rindex = 0; 866 p.name_table = NULL; 867 868 ret = append_rdata(&p, record); 869 870 if (p.name_table) 871 avahi_hashmap_free(p.name_table); 872 873 if (ret < 0) 874 return (size_t) -1; 875 876 return p.size; 877 } 878