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