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