| 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 |
| 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: { |
| 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); |
| 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 |
| 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 } |
|