comparison src/protocols/rendezvous/mdns.c @ 8636:005c96dab551

[gaim-migrate @ 9388] I finished all my overflow checking and what not. If anyone else wants to look over it feel free... Null resource records (buddy icons) should be getting sent now, too. I'm not really sure why I'm not showing up in my iChat buddy list. Gaim rendezvous people show up in gaim rendezvous buddy lists, I think. Eh, I still have to deal with caching and handling queries. And then messaging. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Mon, 12 Apr 2004 01:17:10 +0000
parents bcb09cc97b63
children f39884263db0
comparison
equal deleted inserted replaced
8635:4aee5a47937d 8636:005c96dab551
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 }