/src/avahi/fuzz/fuzz-packet.c
Line | Count | Source (jump to first uncovered line) |
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 | | #include <stdbool.h> |
21 | | #include <stdint.h> |
22 | | #include <string.h> |
23 | | |
24 | | #include "avahi-common/defs.h" |
25 | | #include "avahi-common/domain.h" |
26 | | #include "avahi-common/malloc.h" |
27 | | #include "avahi-core/dns.h" |
28 | | #include "avahi-core/domain-util.h" |
29 | | #include "avahi-core/log.h" |
30 | | |
31 | 111 | void log_function(AvahiLogLevel level, const char *txt) {} |
32 | | |
33 | 135k | void domain_ends_with_mdns_suffix(const char *domain) { |
34 | 135k | avahi_domain_ends_with(domain, AVAHI_MDNS_SUFFIX_LOCAL); |
35 | 135k | avahi_domain_ends_with(domain, AVAHI_MDNS_SUFFIX_ADDR_IPV4); |
36 | 135k | avahi_domain_ends_with(domain, AVAHI_MDNS_SUFFIX_ADDR_IPV6); |
37 | 135k | } |
38 | | |
39 | 2.11k | bool copy_rrs(AvahiDnsPacket *from, AvahiDnsPacket *to, unsigned idx) { |
40 | 33.8k | for (uint16_t n = avahi_dns_packet_get_field(from, idx); n > 0; n--) { |
41 | 33.3k | AvahiRecord *record; |
42 | 33.3k | int cache_flush = 0; |
43 | 33.3k | uint8_t *res; |
44 | | |
45 | 33.3k | if (!(record = avahi_dns_packet_consume_record(from, &cache_flush))) |
46 | 1.11k | return false; |
47 | | |
48 | 32.2k | avahi_free(avahi_record_to_string(record)); |
49 | | |
50 | 32.2k | domain_ends_with_mdns_suffix(record->key->name); |
51 | | |
52 | | // This resembles the RR callbacks responsible for browsing services |
53 | 32.2k | if (record->key->type == AVAHI_DNS_TYPE_PTR) { |
54 | 5.02k | char service[AVAHI_LABEL_MAX], type[AVAHI_DOMAIN_NAME_MAX], domain[AVAHI_DOMAIN_NAME_MAX]; |
55 | 5.02k | char name[AVAHI_DOMAIN_NAME_MAX]; |
56 | 5.02k | int res; |
57 | | |
58 | 5.02k | if (avahi_service_name_split(record->data.ptr.name, service, sizeof(service), type, sizeof(type), domain, sizeof(domain)) >= 0) { |
59 | 1.09k | res = avahi_service_name_join(name, sizeof(name), service, type, domain); |
60 | 1.09k | assert(res >= 0); |
61 | 1.09k | } |
62 | | |
63 | 5.02k | if (avahi_service_name_split(record->data.ptr.name, NULL, 0, type, sizeof(type), domain, sizeof(domain)) >= 0) { |
64 | 710 | res = avahi_service_name_join(name, sizeof(name), NULL, type, domain); |
65 | 710 | assert(res >= 0); |
66 | 710 | } |
67 | 5.02k | } |
68 | | |
69 | 32.2k | res = avahi_dns_packet_append_record(to, record, cache_flush, 0); |
70 | 32.2k | avahi_record_unref(record); |
71 | 32.2k | if (!res) |
72 | 514 | return false; |
73 | 31.7k | avahi_dns_packet_inc_field(to, idx); |
74 | 31.7k | } |
75 | 490 | return true; |
76 | 2.11k | } |
77 | | |
78 | 2.54k | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
79 | 2.54k | AvahiDnsPacket *p1 = NULL, *p2 = NULL; |
80 | | |
81 | 2.54k | if (size > AVAHI_DNS_PACKET_SIZE_MAX) |
82 | 3 | return 0; |
83 | | |
84 | 2.54k | avahi_set_log_function(log_function); |
85 | | |
86 | 2.54k | if (!(p1 = avahi_dns_packet_new(size + AVAHI_DNS_PACKET_EXTRA_SIZE))) |
87 | 0 | goto finish; |
88 | | |
89 | 2.54k | memcpy(AVAHI_DNS_PACKET_DATA(p1), data, size); |
90 | 2.54k | p1->size = size; |
91 | | |
92 | 2.54k | if (avahi_dns_packet_check_valid(p1) < 0) |
93 | 20 | goto finish; |
94 | | |
95 | 2.52k | if (!(p2 = avahi_dns_packet_new(size + AVAHI_DNS_PACKET_EXTRA_SIZE))) |
96 | 0 | goto finish; |
97 | | |
98 | 2.52k | avahi_dns_packet_set_field(p2, AVAHI_DNS_FIELD_ID, avahi_dns_packet_get_field(p1, AVAHI_DNS_FIELD_ID)); |
99 | | |
100 | 105k | for (uint16_t n = avahi_dns_packet_get_field(p1, AVAHI_DNS_FIELD_QDCOUNT); n > 0; n--) { |
101 | 104k | AvahiKey *key; |
102 | 104k | int unicast_response = 0; |
103 | 104k | uint8_t *res; |
104 | | |
105 | 104k | if (!(key = avahi_dns_packet_consume_key(p1, &unicast_response))) |
106 | 823 | goto finish; |
107 | | |
108 | 103k | avahi_free(avahi_key_to_string(key)); |
109 | | |
110 | 103k | domain_ends_with_mdns_suffix(key->name); |
111 | | |
112 | 103k | res = avahi_dns_packet_append_key(p2, key, unicast_response); |
113 | 103k | avahi_key_unref(key); |
114 | 103k | if (!res) |
115 | 60 | goto finish; |
116 | 103k | avahi_dns_packet_inc_field(p2, AVAHI_DNS_FIELD_QDCOUNT); |
117 | 103k | } |
118 | | |
119 | 1.63k | if (!copy_rrs(p1, p2, AVAHI_DNS_FIELD_ANCOUNT)) |
120 | 1.26k | goto finish; |
121 | | |
122 | 372 | if (!copy_rrs(p1, p2, AVAHI_DNS_FIELD_NSCOUNT)) |
123 | 262 | goto finish; |
124 | | |
125 | 110 | if (!copy_rrs(p1, p2, AVAHI_DNS_FIELD_ARCOUNT)) |
126 | 102 | goto finish; |
127 | | |
128 | 2.54k | finish: |
129 | 2.54k | if (p2) |
130 | 2.52k | avahi_dns_packet_free(p2); |
131 | 2.54k | if (p1) |
132 | 2.54k | avahi_dns_packet_free(p1); |
133 | | |
134 | 2.54k | return 0; |
135 | 110 | } |