/src/avahi/fuzz/fuzz-packet.c
Line | Count | Source |
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 | | #ifdef HAVE_NALLOCFUZZ |
32 | | #include "nallocinc.c" |
33 | | #endif |
34 | | |
35 | 0 | void log_function(AvahiLogLevel level, const char *txt) {} |
36 | | |
37 | 0 | void domain_ends_with_mdns_suffix(const char *domain) { |
38 | 0 | avahi_domain_ends_with(domain, AVAHI_MDNS_SUFFIX_LOCAL); |
39 | 0 | avahi_domain_ends_with(domain, AVAHI_MDNS_SUFFIX_ADDR_IPV4); |
40 | 0 | avahi_domain_ends_with(domain, AVAHI_MDNS_SUFFIX_ADDR_IPV6); |
41 | 0 | } |
42 | | |
43 | 0 | bool copy_rrs(AvahiDnsPacket *from, AvahiDnsPacket *to, unsigned idx) { |
44 | 0 | for (uint16_t n = avahi_dns_packet_get_field(from, idx); n > 0; n--) { |
45 | 0 | AvahiRecord *record; |
46 | 0 | int cache_flush = 0; |
47 | 0 | uint8_t *res; |
48 | |
|
49 | 0 | if (!(record = avahi_dns_packet_consume_record(from, &cache_flush))) |
50 | 0 | return false; |
51 | | |
52 | 0 | avahi_free(avahi_record_to_string(record)); |
53 | |
|
54 | 0 | domain_ends_with_mdns_suffix(record->key->name); |
55 | | |
56 | | // This resembles the RR callbacks responsible for browsing services |
57 | 0 | if (record->key->type == AVAHI_DNS_TYPE_PTR) { |
58 | 0 | char service[AVAHI_LABEL_MAX], type[AVAHI_DOMAIN_NAME_MAX], domain[AVAHI_DOMAIN_NAME_MAX]; |
59 | 0 | char name[AVAHI_DOMAIN_NAME_MAX]; |
60 | 0 | int res; |
61 | |
|
62 | 0 | if (avahi_service_name_split(record->data.ptr.name, service, sizeof(service), type, sizeof(type), domain, sizeof(domain)) >= 0) { |
63 | 0 | res = avahi_service_name_join(name, sizeof(name), service, type, domain); |
64 | 0 | assert(res >= 0); |
65 | 0 | } |
66 | |
|
67 | 0 | if (avahi_service_name_split(record->data.ptr.name, NULL, 0, type, sizeof(type), domain, sizeof(domain)) >= 0) { |
68 | 0 | res = avahi_service_name_join(name, sizeof(name), NULL, type, domain); |
69 | 0 | assert(res >= 0); |
70 | 0 | } |
71 | 0 | } |
72 | |
|
73 | 0 | res = avahi_dns_packet_append_record(to, record, cache_flush, 0); |
74 | 0 | avahi_record_unref(record); |
75 | 0 | if (!res) |
76 | 0 | return false; |
77 | 0 | avahi_dns_packet_inc_field(to, idx); |
78 | 0 | } |
79 | 0 | return true; |
80 | 0 | } |
81 | | |
82 | 0 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
83 | 0 | AvahiDnsPacket *p1 = NULL, *p2 = NULL; |
84 | |
|
85 | 0 | if (size > AVAHI_DNS_PACKET_SIZE_MAX) |
86 | 0 | return 0; |
87 | | |
88 | 0 | avahi_set_log_function(log_function); |
89 | |
|
90 | 0 | if (!(p1 = avahi_dns_packet_new(size + AVAHI_DNS_PACKET_EXTRA_SIZE))) |
91 | 0 | goto finish; |
92 | | |
93 | 0 | memcpy(AVAHI_DNS_PACKET_DATA(p1), data, size); |
94 | 0 | p1->size = size; |
95 | |
|
96 | | #ifdef HAVE_NALLOCFUZZ |
97 | | nalloc_start(data, size); |
98 | | #endif |
99 | |
|
100 | 0 | if (avahi_dns_packet_check_valid(p1) < 0) |
101 | 0 | goto finish; |
102 | | |
103 | 0 | if (!(p2 = avahi_dns_packet_new(size + AVAHI_DNS_PACKET_EXTRA_SIZE))) |
104 | 0 | goto finish; |
105 | | |
106 | 0 | avahi_dns_packet_set_field(p2, AVAHI_DNS_FIELD_ID, avahi_dns_packet_get_field(p1, AVAHI_DNS_FIELD_ID)); |
107 | |
|
108 | 0 | for (uint16_t n = avahi_dns_packet_get_field(p1, AVAHI_DNS_FIELD_QDCOUNT); n > 0; n--) { |
109 | 0 | AvahiKey *key; |
110 | 0 | int unicast_response = 0; |
111 | 0 | uint8_t *res; |
112 | |
|
113 | 0 | if (!(key = avahi_dns_packet_consume_key(p1, &unicast_response))) |
114 | 0 | goto finish; |
115 | | |
116 | 0 | avahi_free(avahi_key_to_string(key)); |
117 | |
|
118 | 0 | domain_ends_with_mdns_suffix(key->name); |
119 | |
|
120 | 0 | res = avahi_dns_packet_append_key(p2, key, unicast_response); |
121 | 0 | avahi_key_unref(key); |
122 | 0 | if (!res) |
123 | 0 | goto finish; |
124 | 0 | avahi_dns_packet_inc_field(p2, AVAHI_DNS_FIELD_QDCOUNT); |
125 | 0 | } |
126 | | |
127 | 0 | if (!copy_rrs(p1, p2, AVAHI_DNS_FIELD_ANCOUNT)) |
128 | 0 | goto finish; |
129 | | |
130 | 0 | if (!copy_rrs(p1, p2, AVAHI_DNS_FIELD_NSCOUNT)) |
131 | 0 | goto finish; |
132 | | |
133 | 0 | if (!copy_rrs(p1, p2, AVAHI_DNS_FIELD_ARCOUNT)) |
134 | 0 | goto finish; |
135 | | |
136 | 0 | finish: |
137 | 0 | if (p2) |
138 | 0 | avahi_dns_packet_free(p2); |
139 | 0 | if (p1) |
140 | 0 | avahi_dns_packet_free(p1); |
141 | |
|
142 | | #ifdef HAVE_NALLOCFUZZ |
143 | | nalloc_end(); |
144 | | #endif |
145 | |
|
146 | 0 | return 0; |
147 | 0 | } |