src/protocols/rendezvous/mdns.c

changeset 8636
d49af923e2ce
parent 8634
2781838b4e10
child 8679
c1832805cad1
equal deleted inserted replaced
8635:a0c7f0bfedfa 8636:d49af923e2ce
28 * draft-cheshire-dnsext-multicastdns.txt, and buy 28 * draft-cheshire-dnsext-multicastdns.txt, and buy
29 * me a doughnut. thx k bye. 29 * me a doughnut. thx k bye.
30 */ 30 */
31 31
32 /* 32 /*
33 * XXX - THIS DOESN'T DO BOUNDS CHECKING!!! DON'T USE IT ON AN UNTRUSTED 33 * XXX - This entire file could use another pair of eyes to audit for
34 * NETWORK UNTIL IT DOES!!! THERE ARE POSSIBLE REMOTE ACCESS VIA BUFFER 34 * any possible buffer overflow exploits.
35 * OVERFLOW SECURITY HOLES!!!
36 */ 35 */
37 36
38 #include "internal.h" 37 #include "internal.h"
39 #include "debug.h" 38 #include "debug.h"
40 39
41 #include "mdns.h" 40 #include "mdns.h"
42 #include "util.h" 41 #include "util.h"
42
43 /******************************************/
44 /* Functions for freeing a DNS structure */
45 /******************************************/
46
47 /**
48 * Free the rdata associated with a given resource record.
49 */
50 static void
51 mdns_free_rr_rdata(unsigned short type, void *rdata)
52 {
53 if (rdata == NULL)
54 return;
55
56 switch (type) {
57 case RENDEZVOUS_RRTYPE_NULL:
58 case RENDEZVOUS_RRTYPE_PTR:
59 g_free(rdata);
60 break;
61
62 case RENDEZVOUS_RRTYPE_TXT:
63 g_hash_table_destroy(rdata);
64 break;
65
66 case RENDEZVOUS_RRTYPE_SRV:
67 g_free(((ResourceRecordRDataSRV *)rdata)->target);
68 g_free(rdata);
69 break;
70 }
71 }
72
73 /**
74 * Free a given question
75 */
76 static void
77 mdns_free_q(Question *q)
78 {
79 g_free(q->name);
80 }
81
82 /**
83 * Free a given resource record.
84 */
85 static void
86 mdns_free_rr(ResourceRecord *rr)
87 {
88 g_free(rr->name);
89 mdns_free_rr_rdata(rr->type, rr->rdata);
90 }
91
92 void
93 mdns_free(DNSPacket *dns)
94 {
95 int i;
96
97 for (i = 0; i < dns->header.numquestions; i++)
98 mdns_free_q(&dns->questions[i]);
99 for (i = 0; i < dns->header.numanswers; i++)
100 mdns_free_rr(&dns->answers[i]);
101 for (i = 0; i < dns->header.numauthority; i++)
102 mdns_free_rr(&dns->authority[i]);
103 for (i = 0; i < dns->header.numadditional; i++)
104 mdns_free_rr(&dns->additional[i]);
105
106 g_free(dns->questions);
107 g_free(dns->answers);
108 g_free(dns->authority);
109 g_free(dns->additional);
110 g_free(dns);
111 }
43 112
44 /******************************************/ 113 /******************************************/
45 /* Functions for connection establishment */ 114 /* Functions for connection establishment */
46 /******************************************/ 115 /******************************************/
47 116
106 } 175 }
107 176
108 return fd; 177 return fd;
109 } 178 }
110 179
180 /**
181 * Multicast raw data over a file descriptor.
182 *
183 * @param fd A file descriptor that is a socket bound to a UDP port.
184 * @param datalen The length of the data you wish to send.
185 * @param data The data you wish to send.
186 * @return 0 on success, otherwise return -1.
187 */
111 static int 188 static int
112 mdns_send_raw(int fd, unsigned int datalen, unsigned char *data) 189 mdns_send_raw(int fd, unsigned int datalen, unsigned char *data)
113 { 190 {
114 struct sockaddr_in addr; 191 struct sockaddr_in addr;
115 int n; 192 int n;
171 } 248 }
172 249
173 static int 250 static int
174 mdns_getlength_RR(ResourceRecord *rr) 251 mdns_getlength_RR(ResourceRecord *rr)
175 { 252 {
176 rr->rdlength = mdns_getlength_RR_rdata(rr->type, rr->rdata);
177
178 return mdns_getlength_name(rr->name) + 10 + rr->rdlength; 253 return mdns_getlength_name(rr->name) + 10 + rr->rdlength;
179 } 254 }
180 255
181 static int 256 static int
182 mdns_put_name(char *data, unsigned int datalen, unsigned int offset, const char *name) 257 mdns_put_name(char *data, unsigned int datalen, unsigned int offset, const char *name)
208 i += util_put16(&data[offset + i], rr->class); 283 i += util_put16(&data[offset + i], rr->class);
209 i += util_put32(&data[offset + i], rr->ttl); 284 i += util_put32(&data[offset + i], rr->ttl);
210 i += util_put16(&data[offset + i], rr->rdlength); 285 i += util_put16(&data[offset + i], rr->rdlength);
211 286
212 switch (rr->type) { 287 switch (rr->type) {
288 case RENDEZVOUS_RRTYPE_NULL:
289 memcpy(&data[offset + i], rr->rdata, rr->rdlength);
290 i += rr->rdlength;
291 break;
292
213 case RENDEZVOUS_RRTYPE_PTR: 293 case RENDEZVOUS_RRTYPE_PTR:
214 i += mdns_put_name(data, datalen, offset + i, (const char *)rr->rdata); 294 i += mdns_put_name(data, datalen, offset + i, (const char *)rr->rdata);
215 break; 295 break;
216 296
217 case RENDEZVOUS_RRTYPE_TXT: { 297 case RENDEZVOUS_RRTYPE_TXT: {
313 393
314 return ret; 394 return ret;
315 } 395 }
316 396
317 int 397 int
318 mdns_query(int fd, const char *domain) 398 mdns_query(int fd, const char *domain, unsigned short type)
319 { 399 {
320 int ret; 400 int ret;
321 DNSPacket *dns; 401 DNSPacket *dns;
322 402
323 if (strlen(domain) > 255) { 403 if (strlen(domain) > 255) {
332 dns->header.numauthority = 0x0000; 412 dns->header.numauthority = 0x0000;
333 dns->header.numadditional = 0x0000; 413 dns->header.numadditional = 0x0000;
334 414
335 dns->questions = (Question *)g_malloc(1 * sizeof(Question)); 415 dns->questions = (Question *)g_malloc(1 * sizeof(Question));
336 dns->questions[0].name = g_strdup(domain); 416 dns->questions[0].name = g_strdup(domain);
337 dns->questions[0].type = RENDEZVOUS_RRTYPE_PTR; 417 dns->questions[0].type = type;
338 dns->questions[0].class = 0x8001; 418 dns->questions[0].class = 0x0001;
339 419
340 dns->answers = NULL; 420 dns->answers = NULL;
341 dns->authority = NULL; 421 dns->authority = NULL;
342 dns->additional = NULL; 422 dns->additional = NULL;
343 423
347 427
348 return ret; 428 return ret;
349 } 429 }
350 430
351 int 431 int
352 mdns_advertise_ptr(int fd, const char *name, const char *domain) 432 mdns_advertise_null(int fd, const char *name, const char *rdata, unsigned short rdlength)
353 { 433 {
354 int ret; 434 int ret;
355 DNSPacket *dns; 435 DNSPacket *dns;
356 436
357 if ((strlen(name) > 255) || (strlen(domain) > 255)) { 437 if ((strlen(name) > 255)) {
358 return -EINVAL; 438 return -EINVAL;
359 } 439 }
360 440
361 dns = (DNSPacket *)g_malloc(sizeof(DNSPacket)); 441 dns = (DNSPacket *)g_malloc(sizeof(DNSPacket));
362 dns->header.id = 0x0000; 442 dns->header.id = 0x0000;
367 dns->header.numadditional = 0x0000; 447 dns->header.numadditional = 0x0000;
368 dns->questions = NULL; 448 dns->questions = NULL;
369 449
370 dns->answers = (ResourceRecord *)g_malloc(1 * sizeof(ResourceRecord)); 450 dns->answers = (ResourceRecord *)g_malloc(1 * sizeof(ResourceRecord));
371 dns->answers[0].name = g_strdup(name); 451 dns->answers[0].name = g_strdup(name);
372 dns->answers[0].type = RENDEZVOUS_RRTYPE_PTR; 452 dns->answers[0].type = RENDEZVOUS_RRTYPE_NULL;
373 dns->answers[0].class = 0x8001; 453 dns->answers[0].class = 0x0001;
374 dns->answers[0].ttl = 0x00001c20; 454 dns->answers[0].ttl = 0x00001c20;
375 dns->answers[0].rdlength = 0x0000; /* Set automatically */ 455 dns->answers[0].rdlength = rdlength;
376 dns->answers[0].rdata = (void *)g_strdup(domain); 456 dns->answers[0].rdata = (void *)rdata;
377 457
378 dns->authority = NULL; 458 dns->authority = NULL;
379 dns->additional = NULL; 459 dns->additional = NULL;
380 460
381 mdns_send_dns(fd, dns); 461 mdns_send_dns(fd, dns);
382 462
463 /* The rdata should be freed by the caller of this function */
464 dns->answers[0].rdata = NULL;
465
383 mdns_free(dns); 466 mdns_free(dns);
384 467
385 return ret; 468 return ret;
386 } 469 }
387 470
388 int 471 int
389 mdns_advertise_txt(int fd, const char *name, const GSList *rdata) 472 mdns_advertise_ptr(int fd, const char *name, const char *domain)
390 { 473 {
391 int ret; 474 int ret;
392 DNSPacket *dns; 475 DNSPacket *dns;
393 476
394 if ((strlen(name) > 255)) { 477 if ((strlen(name) > 255) || (strlen(domain) > 255)) {
395 return -EINVAL; 478 return -EINVAL;
396 } 479 }
397 480
398 dns = (DNSPacket *)g_malloc(sizeof(DNSPacket)); 481 dns = (DNSPacket *)g_malloc(sizeof(DNSPacket));
399 dns->header.id = 0x0000; 482 dns->header.id = 0x0000;
404 dns->header.numadditional = 0x0000; 487 dns->header.numadditional = 0x0000;
405 dns->questions = NULL; 488 dns->questions = NULL;
406 489
407 dns->answers = (ResourceRecord *)g_malloc(1 * sizeof(ResourceRecord)); 490 dns->answers = (ResourceRecord *)g_malloc(1 * sizeof(ResourceRecord));
408 dns->answers[0].name = g_strdup(name); 491 dns->answers[0].name = g_strdup(name);
409 dns->answers[0].type = RENDEZVOUS_RRTYPE_TXT; 492 dns->answers[0].type = RENDEZVOUS_RRTYPE_PTR;
410 dns->answers[0].class = 0x8001; 493 dns->answers[0].class = 0x8001;
411 dns->answers[0].ttl = 0x00001c20; 494 dns->answers[0].ttl = 0x00001c20;
412 dns->answers[0].rdlength = 0x0000; /* Set automatically */ 495 dns->answers[0].rdata = (void *)g_strdup(domain);
413 dns->answers[0].rdata = (void *)rdata; 496 dns->answers[0].rdlength = mdns_getlength_RR_rdata(dns->answers[0].type, dns->answers[0].rdata);
414 497
415 dns->authority = NULL; 498 dns->authority = NULL;
416 dns->additional = NULL; 499 dns->additional = NULL;
417 500
418 mdns_send_dns(fd, dns); 501 mdns_send_dns(fd, dns);
419 502
420 /* The rdata should be freed by the caller of this function */
421 dns->answers[0].rdata = NULL;
422
423 mdns_free(dns); 503 mdns_free(dns);
424 504
425 return ret; 505 return ret;
426 } 506 }
427 507
428 int 508 int
429 mdns_advertise_srv(int fd, const char *name, unsigned short port, const char *target) 509 mdns_advertise_txt(int fd, const char *name, const GSList *rdata)
430 { 510 {
431 int ret; 511 int ret;
432 DNSPacket *dns; 512 DNSPacket *dns;
433 ResourceRecordRDataSRV *rdata; 513
434 514 if ((strlen(name) > 255)) {
435 if ((strlen(target) > 255)) {
436 return -EINVAL; 515 return -EINVAL;
437 } 516 }
438
439 rdata = g_malloc(sizeof(ResourceRecordRDataSRV));
440 rdata->port = port;
441 rdata->target = g_strdup(target);
442 517
443 dns = (DNSPacket *)g_malloc(sizeof(DNSPacket)); 518 dns = (DNSPacket *)g_malloc(sizeof(DNSPacket));
444 dns->header.id = 0x0000; 519 dns->header.id = 0x0000;
445 dns->header.flags = 0x8400; 520 dns->header.flags = 0x8400;
446 dns->header.numquestions = 0x0000; 521 dns->header.numquestions = 0x0000;
449 dns->header.numadditional = 0x0000; 524 dns->header.numadditional = 0x0000;
450 dns->questions = NULL; 525 dns->questions = NULL;
451 526
452 dns->answers = (ResourceRecord *)g_malloc(1 * sizeof(ResourceRecord)); 527 dns->answers = (ResourceRecord *)g_malloc(1 * sizeof(ResourceRecord));
453 dns->answers[0].name = g_strdup(name); 528 dns->answers[0].name = g_strdup(name);
454 dns->answers[0].type = RENDEZVOUS_RRTYPE_SRV; 529 dns->answers[0].type = RENDEZVOUS_RRTYPE_TXT;
455 dns->answers[0].class = 0x8001; 530 dns->answers[0].class = 0x8001;
456 dns->answers[0].ttl = 0x00001c20; 531 dns->answers[0].ttl = 0x00001c20;
457 dns->answers[0].rdlength = 0x0000; /* Set automatically */ 532 dns->answers[0].rdata = (void *)rdata;
458 dns->answers[0].rdata = rdata; 533 dns->answers[0].rdlength = mdns_getlength_RR_rdata(dns->answers[0].type, dns->answers[0].rdata);
459 534
460 dns->authority = NULL; 535 dns->authority = NULL;
536 dns->additional = NULL;
537
538 mdns_send_dns(fd, dns);
539
540 /* The rdata should be freed by the caller of this function */
541 dns->answers[0].rdata = NULL;
542
543 mdns_free(dns);
544
545 return ret;
546 }
547
548 int
549 mdns_advertise_srv(int fd, const char *name, unsigned short port, const char *target)
550 {
551 int ret;
552 DNSPacket *dns;
553 ResourceRecordRDataSRV *rdata;
554
555 if ((strlen(target) > 255)) {
556 return -EINVAL;
557 }
558
559 rdata = g_malloc(sizeof(ResourceRecordRDataSRV));
560 rdata->port = port;
561 rdata->target = g_strdup(target);
562
563 dns = (DNSPacket *)g_malloc(sizeof(DNSPacket));
564 dns->header.id = 0x0000;
565 dns->header.flags = 0x8400;
566 dns->header.numquestions = 0x0000;
567 dns->header.numanswers = 0x0000;
568 dns->header.numauthority = 0x0001;
569 dns->header.numadditional = 0x0000;
570 dns->questions = NULL;
571 dns->answers = NULL;
572
573 dns->authority = (ResourceRecord *)g_malloc(1 * sizeof(ResourceRecord));
574 dns->authority[0].name = g_strdup(name);
575 dns->authority[0].type = RENDEZVOUS_RRTYPE_SRV;
576 dns->authority[0].class = 0x8001;
577 dns->authority[0].ttl = 0x00001c20;
578 dns->authority[0].rdata = rdata;
579 dns->authority[0].rdlength = mdns_getlength_RR_rdata(dns->authority[0].type, dns->authority[0].rdata);
580
461 dns->additional = NULL; 581 dns->additional = NULL;
462 582
463 mdns_send_dns(fd, dns); 583 mdns_send_dns(fd, dns);
464 584
465 mdns_free(dns); 585 mdns_free(dns);
506 } else { /* First two bits are 11 */ 626 } else { /* First two bits are 11 */
507 /* Jump to another position in the data */ 627 /* Jump to another position in the data */
508 newoffset = util_get8(&data[offset]); 628 newoffset = util_get8(&data[offset]);
509 if (newoffset >= offset) 629 if (newoffset >= offset)
510 /* Invalid pointer! Could lead to infinite recursion! Bailing! */ 630 /* Invalid pointer! Could lead to infinite recursion! Bailing! */
511 g_string_free(ret, TRUE); 631 return g_string_free(ret, TRUE);
512 offset = newoffset; 632 offset = newoffset;
513 } 633 }
514 } 634 }
635
636 if (offset > datalen)
637 return g_string_free(ret, TRUE);
515 638
516 return g_string_free(ret, FALSE); 639 return g_string_free(ret, FALSE);
517 } 640 }
518 641
519 /* 642 /*
553 676
554 return offset - startoffset + 1; 677 return offset - startoffset + 1;
555 } 678 }
556 679
557 /* 680 /*
558 * XXX - Needs bounds checking! 681 *
559 * 682 *
560 */ 683 */
561 static Question * 684 static Question *
562 mdns_read_questions(int numquestions, const char *data, unsigned int datalen, int *offset) 685 mdns_read_questions(int numquestions, const char *data, unsigned int datalen, int *offset)
563 { 686 {
566 689
567 ret = (Question *)g_malloc0(numquestions * sizeof(Question)); 690 ret = (Question *)g_malloc0(numquestions * sizeof(Question));
568 for (i = 0; i < numquestions; i++) { 691 for (i = 0; i < numquestions; i++) {
569 ret[i].name = mdns_read_name(data, datalen, *offset); 692 ret[i].name = mdns_read_name(data, datalen, *offset);
570 *offset += mdns_read_name_len(data, datalen, *offset); 693 *offset += mdns_read_name_len(data, datalen, *offset);
694 if (*offset + 4 > datalen)
695 break;
571 ret[i].type = util_get16(&data[*offset]); /* QTYPE */ 696 ret[i].type = util_get16(&data[*offset]); /* QTYPE */
572 *offset += 2; 697 *offset += 2;
573 ret[i].class = util_get16(&data[*offset]); /* QCLASS */ 698 ret[i].class = util_get16(&data[*offset]); /* QCLASS */
574 *offset += 2; 699 *offset += 2;
700 if (*offset > datalen)
701 break;
702 }
703
704 /* Malformed packet check */
705 if (i < numquestions) {
706 for (i = 0; i < numquestions; i++)
707 g_free(ret[i].name);
708 g_free(ret);
709 return NULL;
575 } 710 }
576 711
577 return ret; 712 return ret;
578 } 713 }
579 714
594 729
595 return ret; 730 return ret;
596 } 731 }
597 732
598 /* 733 /*
599 * XXX - Needs bounds checking! 734 * Read in a compressed name.
600 * 735 *
601 */ 736 */
602 static char * 737 static char *
603 mdns_read_rr_rdata_ptr(const char *data, unsigned int datalen, unsigned int offset) 738 mdns_read_rr_rdata_ptr(const char *data, unsigned int datalen, unsigned int offset)
604 { 739 {
605 char *ret = NULL; 740 return mdns_read_name(data, datalen, offset);
606
607 ret = mdns_read_name(data, datalen, offset);
608
609 return ret;
610 } 741 }
611 742
612 /* 743 /*
613 * 744 * Read in a list of name=value pairs into a GHashTable.
614 * 745 *
615 */ 746 */
616 static GHashTable * 747 static GHashTable *
617 mdns_read_rr_rdata_txt(const char *data, unsigned int datalen, unsigned int offset, unsigned short rdlength) 748 mdns_read_rr_rdata_txt(const char *data, unsigned int datalen, unsigned int offset, unsigned short rdlength)
618 { 749 {
624 while (offset < endoffset) { 755 while (offset < endoffset) {
625 /* Read in the length of the next name/value pair */ 756 /* Read in the length of the next name/value pair */
626 tmp = util_get8(&data[offset]); 757 tmp = util_get8(&data[offset]);
627 offset++; 758 offset++;
628 759
629 /* Ensure packet is valid */ 760 /* Malformed packet check */
630 if (offset + tmp > endoffset) 761 if (offset + tmp > endoffset)
631 break; 762 break;
632 763
633 /* Read in the next name/value pair */ 764 /* Read in the next name/value pair */
634 strncpy(buf, &data[offset], tmp); 765 strncpy(buf, &data[offset], tmp);
653 g_hash_table_insert(ret, key, g_strdup(value)); 784 g_hash_table_insert(ret, key, g_strdup(value));
654 else 785 else
655 g_free(key); 786 g_free(key);
656 } 787 }
657 788
789 /* Malformed packet check */
790 if ((offset > datalen) || (offset != endoffset)) {
791 g_hash_table_destroy(ret);
792 return NULL;
793 }
794
658 return ret; 795 return ret;
659 } 796 }
660 797
661 /* 798 /*
662 * 799 *
666 mdns_read_rr_rdata_srv(const char *data, unsigned int datalen, unsigned int offset, unsigned short rdlength) 803 mdns_read_rr_rdata_srv(const char *data, unsigned int datalen, unsigned int offset, unsigned short rdlength)
667 { 804 {
668 ResourceRecordSRV *ret = NULL; 805 ResourceRecordSRV *ret = NULL;
669 int endoffset = offset + rdlength; 806 int endoffset = offset + rdlength;
670 807
808 /* Malformed packet check */
671 if (offset + 7 > endoffset) 809 if (offset + 7 > endoffset)
672 return NULL; 810 return NULL;
673 811
674 ret = g_malloc(sizeof(ResourceRecordSRV)); 812 ret = g_malloc(sizeof(ResourceRecordSRV));
675 813
689 /* 827 /*
690 * XXX - RFC2782 says it's not supposed to be an alias... 828 * XXX - RFC2782 says it's not supposed to be an alias...
691 * but it was in the packet capture I looked at from iChat. 829 * but it was in the packet capture I looked at from iChat.
692 */ 830 */
693 ret->target = mdns_read_name(data, datalen, offset); 831 ret->target = mdns_read_name(data, datalen, offset);
832 offset += mdns_read_name_len(data, datalen, offset);
833
834 /* Malformed packet check */
835 if ((offset > endoffset) || (ret->target == NULL)) {
836 g_free(ret->target);
837 g_free(ret);
838 return NULL;
839 }
694 840
695 return ret; 841 return ret;
696 } 842 }
697 843
698 /* 844 /*
699 * XXX - Needs bounds checking! 845 *
700 * 846 *
701 */ 847 */
702 static ResourceRecord * 848 static ResourceRecord *
703 mdns_read_rr(int numrecords, const char *data, unsigned int datalen, int *offset) 849 mdns_read_rr(int numrecords, const char *data, unsigned int datalen, int *offset)
704 { 850 {
705 ResourceRecord *ret; 851 ResourceRecord *ret;
706 int i; 852 int i;
707 853
708 ret = (ResourceRecord *)g_malloc0(numrecords * sizeof(ResourceRecord)); 854 ret = (ResourceRecord *)g_malloc0(numrecords * sizeof(ResourceRecord));
709 for (i = 0; i < numrecords; i++) { 855 for (i = 0; i < numrecords; i++) {
710 ret[i].name = mdns_read_name(data, datalen, *offset); /* NAME */ 856 /* NAME */
857 ret[i].name = mdns_read_name(data, datalen, *offset);
711 *offset += mdns_read_name_len(data, datalen, *offset); 858 *offset += mdns_read_name_len(data, datalen, *offset);
712 ret[i].type = util_get16(&data[*offset]); /* TYPE */ 859
860 /* Malformed packet check */
861 if (*offset + 10 > datalen)
862 break;
863
864 /* TYPE */
865 ret[i].type = util_get16(&data[*offset]);
713 *offset += 2; 866 *offset += 2;
714 ret[i].class = util_get16(&data[*offset]); /* CLASS */ 867
868 /* CLASS */
869 ret[i].class = util_get16(&data[*offset]);
715 *offset += 2; 870 *offset += 2;
716 ret[i].ttl = util_get32(&data[*offset]); /* TTL */ 871
872 /* TTL */
873 ret[i].ttl = util_get32(&data[*offset]);
717 *offset += 4; 874 *offset += 4;
718 ret[i].rdlength = util_get16(&data[*offset]); /* RDLENGTH */ 875
876 /* RDLENGTH */
877 ret[i].rdlength = util_get16(&data[*offset]);
719 *offset += 2; 878 *offset += 2;
720 879
721 /* RDATA */ 880 /* RDATA */
722 switch (ret[i].type) { 881 if (ret[i].type == RENDEZVOUS_RRTYPE_NULL) {
723 case RENDEZVOUS_RRTYPE_NULL: 882 ret[i].rdata = mdns_read_rr_rdata_null(data, datalen, *offset, ret[i].rdlength);
724 ret[i].rdata = mdns_read_rr_rdata_null(data, datalen, *offset, ret[i].rdlength); 883 if (ret[i].rdata == NULL)
884 break;
885
886 } else if (ret[i].type == RENDEZVOUS_RRTYPE_PTR) {
887 ret[i].rdata = mdns_read_rr_rdata_ptr(data, datalen, *offset);
888 if (ret[i].rdata == NULL)
889 break;
890
891 } else if (ret[i].type == RENDEZVOUS_RRTYPE_TXT) {
892 ret[i].rdata = mdns_read_rr_rdata_txt(data, datalen, *offset, ret[i].rdlength);
893 if (ret[i].rdata == NULL)
894 break;
895
896 } else if (ret[i].type == RENDEZVOUS_RRTYPE_SRV) {
897 ret[i].rdata = mdns_read_rr_rdata_srv(data, datalen, *offset, ret[i].rdlength);
898 if (ret[i].rdata == NULL)
899 break;
900
901 }
902
903 /* Malformed packet check */
904 *offset += ret[i].rdlength;
905 if (*offset > datalen)
725 break; 906 break;
726 907 }
727 case RENDEZVOUS_RRTYPE_PTR: 908
728 ret[i].rdata = mdns_read_rr_rdata_ptr(data, datalen, *offset); 909 /* Malformed packet check */
729 break; 910 if (i < numrecords) {
730 911 for (i = 0; i < numrecords; i++) {
731 case RENDEZVOUS_RRTYPE_TXT: 912 g_free(ret[i].name);
732 ret[i].rdata = mdns_read_rr_rdata_txt(data, datalen, *offset, ret[i].rdlength); 913 mdns_free_rr_rdata(ret[i].type, ret[i].rdata);
733 break;
734
735 case RENDEZVOUS_RRTYPE_SRV:
736 ret[i].rdata = mdns_read_rr_rdata_srv(data, datalen, *offset, ret[i].rdlength);
737 break;
738
739 default:
740 ret[i].rdata = NULL;
741 break;
742 } 914 }
743 *offset += ret[i].rdlength; 915 g_free(ret);
916 return NULL;
744 } 917 }
745 918
746 return ret; 919 return ret;
747 } 920 }
748 921
749 /* 922 /*
750 * XXX - Needs bounds checking! 923 *
751 * 924 *
752 */ 925 */
753 DNSPacket * 926 DNSPacket *
754 mdns_read(int fd) 927 mdns_read(int fd)
755 { 928 {
756 DNSPacket *ret = NULL; 929 DNSPacket *ret = NULL;
757 int i; /* Current position in datagram */ 930 int offset; /* Current position in datagram */
758 /* XXX - Find out what to use as a maximum incoming UDP packet size */ 931 /* XXX - Find out what to use as a maximum incoming UDP packet size */
759 /* char data[512]; */ 932 /* char data[512]; */
760 char data[10096]; 933 char data[10096];
761 unsigned int datalen; 934 unsigned int datalen;
762 struct sockaddr_in addr; 935 struct sockaddr_in addr;
770 } 943 }
771 944
772 ret = (DNSPacket *)g_malloc0(sizeof(DNSPacket)); 945 ret = (DNSPacket *)g_malloc0(sizeof(DNSPacket));
773 946
774 /* Parse the incoming packet, starting from 0 */ 947 /* Parse the incoming packet, starting from 0 */
775 i = 0; 948 offset = 0;
949
950 if (offset + 12 > datalen) {
951 g_free(ret);
952 return NULL;
953 }
776 954
777 /* The header section */ 955 /* The header section */
778 ret->header.id = util_get16(&data[i]); /* ID */ 956 ret->header.id = util_get16(&data[offset]); /* ID */
779 i += 2; 957 offset += 2;
780 958
781 /* For the flags, some bits must be 0 and some must be 1, the rest are ignored */ 959 /* For the flags, some bits must be 0 and some must be 1, the rest are ignored */
782 ret->header.flags = util_get16(&data[i]); /* Flags (QR, OPCODE, AA, TC, RD, RA, Z, AD, CD, and RCODE */ 960 ret->header.flags = util_get16(&data[offset]); /* Flags (QR, OPCODE, AA, TC, RD, RA, Z, AD, CD, and RCODE */
783 i += 2; 961 offset += 2;
784 if ((ret->header.flags & 0x8000) == 0) { 962 if ((ret->header.flags & 0x8000) == 0) {
785 /* QR should be 1 */ 963 /* QR should be 1 */
786 g_free(ret); 964 g_free(ret);
787 return NULL; 965 return NULL;
788 } 966 }
791 g_free(ret); 969 g_free(ret);
792 return NULL; 970 return NULL;
793 } 971 }
794 972
795 /* Read in the number of other things in the packet */ 973 /* Read in the number of other things in the packet */
796 ret->header.numquestions = util_get16(&data[i]); 974 ret->header.numquestions = util_get16(&data[offset]);
797 i += 2; 975 offset += 2;
798 ret->header.numanswers = util_get16(&data[i]); 976 ret->header.numanswers = util_get16(&data[offset]);
799 i += 2; 977 offset += 2;
800 ret->header.numauthority = util_get16(&data[i]); 978 ret->header.numauthority = util_get16(&data[offset]);
801 i += 2; 979 offset += 2;
802 ret->header.numadditional = util_get16(&data[i]); 980 ret->header.numadditional = util_get16(&data[offset]);
803 i += 2; 981 offset += 2;
804 982
805 /* Read in all the questions */ 983 /* Read in all the questions */
806 ret->questions = mdns_read_questions(ret->header.numquestions, data, datalen, &i); 984 ret->questions = mdns_read_questions(ret->header.numquestions, data, datalen, &offset);
807 985
808 /* Read in all resource records */ 986 /* Read in all resource records */
809 ret->answers = mdns_read_rr(ret->header.numanswers, data, datalen, &i); 987 ret->answers = mdns_read_rr(ret->header.numanswers, data, datalen, &offset);
810 988
811 /* Read in all authority records */ 989 /* Read in all authority records */
812 ret->authority = mdns_read_rr(ret->header.numauthority, data, datalen, &i); 990 ret->authority = mdns_read_rr(ret->header.numauthority, data, datalen, &offset);
813 991
814 /* Read in all additional records */ 992 /* Read in all additional records */
815 ret->additional = mdns_read_rr(ret->header.numadditional, data, datalen, &i); 993 ret->additional = mdns_read_rr(ret->header.numadditional, data, datalen, &offset);
994
995 /* Malformed packet check */
996 if ((ret->header.numquestions > 0 && ret->questions == NULL) ||
997 (ret->header.numanswers > 0 && ret->answers == NULL) ||
998 (ret->header.numauthority > 0 && ret->authority == NULL) ||
999 (ret->header.numadditional > 0 && ret->additional == NULL)) {
1000 gaim_debug_error("mdns", "Received an invalid DNS packet.\n");
1001 return NULL;
1002 }
816 1003
817 /* We should be at the end of the packet */ 1004 /* We should be at the end of the packet */
818 if (i != datalen) { 1005 if (offset != datalen) {
819 gaim_debug_error("mdns", "Finished parsing before end of DNS packet! Only parsed %d of %d bytes.", i, datalen); 1006 gaim_debug_error("mdns", "Finished parsing before end of DNS packet! Only parsed %d of %d bytes.", offset, datalen);
820 g_free(ret); 1007 g_free(ret);
821 return NULL; 1008 return NULL;
822 } 1009 }
823 1010
824 return ret; 1011 return ret;
825 } 1012 }
826
827 /**
828 * Free the rdata associated with a given resource record.
829 */
830 static void
831 mdns_free_rr_rdata(unsigned short type, void *rdata)
832 {
833 switch (type) {
834 case RENDEZVOUS_RRTYPE_NULL:
835 case RENDEZVOUS_RRTYPE_PTR:
836 g_free(rdata);
837 break;
838
839 case RENDEZVOUS_RRTYPE_TXT:
840 g_hash_table_destroy(rdata);
841 break;
842
843 case RENDEZVOUS_RRTYPE_SRV:
844 g_free(((ResourceRecordRDataSRV *)rdata)->target);
845 g_free(rdata);
846 break;
847 }
848 }
849
850 /**
851 * Free a given question
852 */
853 static void
854 mdns_free_q(Question *q)
855 {
856 g_free(q->name);
857 }
858
859 /**
860 * Free a given resource record.
861 */
862 static void
863 mdns_free_rr(ResourceRecord *rr)
864 {
865 g_free(rr->name);
866 if (rr->rdata != NULL)
867 mdns_free_rr_rdata(rr->type, rr->rdata);
868 }
869
870 void
871 mdns_free(DNSPacket *dns)
872 {
873 int i;
874
875 for (i = 0; i < dns->header.numquestions; i++)
876 mdns_free_q(&dns->questions[i]);
877 for (i = 0; i < dns->header.numanswers; i++)
878 mdns_free_rr(&dns->answers[i]);
879 for (i = 0; i < dns->header.numauthority; i++)
880 mdns_free_rr(&dns->authority[i]);
881 for (i = 0; i < dns->header.numadditional; i++)
882 mdns_free_rr(&dns->additional[i]);
883
884 g_free(dns->questions);
885 g_free(dns->answers);
886 g_free(dns->authority);
887 g_free(dns->additional);
888 g_free(dns);
889 }

mercurial