/src/mongoose/test/fuzz.c
Line | Count | Source |
1 | | // https://llvm.org/docs/LibFuzzer.html |
2 | | |
3 | | #define MG_ENABLE_SOCKET 0 |
4 | | #define MG_ENABLE_LOG 0 |
5 | | #define MG_ENABLE_LINES 1 |
6 | | #define MG_ENABLE_TCPIP 1 |
7 | 5.57k | #define MG_IO_SIZE (32 * 1024 * 1024) // Big IO size for fast resizes |
8 | | |
9 | | #include "mongoose.c" |
10 | | |
11 | | #include "driver_mock.c" |
12 | | |
13 | | #ifdef __cplusplus |
14 | | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *, size_t); |
15 | | #else |
16 | | int LLVMFuzzerTestOneInput(const uint8_t *, size_t); |
17 | | #endif |
18 | | |
19 | 458k | static void fn(struct mg_connection *c, int ev, void *ev_data) { |
20 | 458k | struct mg_http_serve_opts opts = {.root_dir = "."}; |
21 | 458k | if (ev == MG_EV_HTTP_MSG) { |
22 | 214k | mg_http_serve_dir(c, (struct mg_http_message *) ev_data, &opts); |
23 | 214k | } |
24 | 458k | } |
25 | | |
26 | | // deduplicate layer-3 mocking among layer-2s |
27 | | struct fuzz_l3_state { |
28 | | size_t ip_proto, udp_port; |
29 | | size_t ip6_next, icmp6_type; |
30 | | }; |
31 | | |
32 | 140 | static void fuzz_ip4(void *buf, size_t len, struct fuzz_l3_state *st) { |
33 | 140 | if (len >= sizeof(struct ip)) { |
34 | 140 | uint8_t ip_protos[] = {1, 6, 17}; // ICMP, TCP, UDP |
35 | 140 | struct ip *ip4 = (struct ip *) buf; |
36 | 140 | ip4->ver = (uint8_t) ((ip4->ver & ~0xf0) | (4 << 4)); |
37 | | // send all handled IP protos, then 2 random ones |
38 | 140 | if (st->ip_proto >= (sizeof(ip_protos) / sizeof(ip_protos[0]) + 2)) st->ip_proto = 0; |
39 | 140 | if (st->ip_proto < (sizeof(ip_protos) / sizeof(ip_protos[0]))) ip4->proto = ip_protos[st->ip_proto++]; |
40 | 140 | if (ip4->proto == 1) { // ICMP |
41 | 118 | } else if (ip4->proto == 6) { // TCP |
42 | 116 | } else if (ip4->proto == 17 && len >= sizeof(struct ip) + sizeof(struct udp)) { // UDP |
43 | 20 | uint16_t udp_ports[] = {67, 68}; // DHCP server and client |
44 | 20 | struct udp *udp = (struct udp *) (ip4 + 1); |
45 | | // send all handled UDP ports, then 2 random ones |
46 | 20 | if (st->udp_port >= (sizeof(udp_ports) / sizeof(udp_ports[0]) + 2)) st->udp_port = 0; |
47 | 20 | if (st->udp_port < (sizeof(udp_ports) / sizeof(udp_ports[0]))) udp->dport = mg_htons(udp_ports[st->udp_port++]); |
48 | 20 | } |
49 | 140 | } |
50 | 140 | } |
51 | | |
52 | 67 | static void fuzz_ip6(void *buf, size_t len, struct fuzz_l3_state *st) { |
53 | 67 | if (len >= sizeof(struct ip6)) { |
54 | 67 | uint8_t ip6_protos[] = {6, 17, 58}; // TCP, UDP, ICMPv6 |
55 | 67 | struct ip6 *ip6 = (struct ip6 *) buf; |
56 | 67 | ip6->ver = (uint8_t) ((ip6->ver & ~0xf0) | (6 << 4)); |
57 | | // send all handled IPv6 "next headers", then 2 random ones |
58 | 67 | if (st->ip6_next >= (sizeof(ip6_protos) / sizeof(ip6_protos[0]) + 2)) st->ip6_next = 0; |
59 | 67 | if (st->ip6_next < (sizeof(ip6_protos) / sizeof(ip6_protos[0]))) ip6->next = ip6_protos[st->ip6_next++]; |
60 | 67 | if (ip6->next == 6) { // TCP |
61 | 65 | } else if (ip6->next == 17) { // UDP |
62 | 63 | } else if (ip6->next == 58 && len >= sizeof(struct ip6) + sizeof(struct icmp6)) { // ICMPv6 |
63 | 25 | uint8_t icmp6_types[] = {128, 134, 135, 136}; // Echo Request, RA, NS, NA |
64 | 25 | struct icmp6 *icmp6 = (struct icmp6 *) (ip6 + 1); |
65 | | // send all handled ICMPv6 types, then 2 random ones |
66 | 25 | if (st->icmp6_type >= (sizeof(icmp6_types) / sizeof(icmp6_types[0]) + 2)) st->icmp6_type = 0; |
67 | 25 | if (st->icmp6_type < (sizeof(icmp6_types) / sizeof(icmp6_types[0]))) icmp6->type = icmp6_types[st->icmp6_type++]; |
68 | 25 | } |
69 | 67 | } |
70 | 67 | } |
71 | | |
72 | 5.57k | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
73 | 5.57k | mg_log_set(MG_LL_INFO); |
74 | | |
75 | 5.57k | struct mg_dns_message dm; |
76 | 5.57k | mg_dns_parse(data, size, &dm); |
77 | 5.57k | mg_dns_parse(NULL, 0, &dm); |
78 | | |
79 | 5.57k | struct mg_http_message hm; |
80 | 5.57k | if (mg_http_parse((const char *) data, size, &hm) > 0) { |
81 | 2.04k | mg_crc32(0, hm.method.buf, hm.method.len); |
82 | 2.04k | mg_crc32(0, hm.uri.buf, hm.uri.len); |
83 | 2.04k | mg_crc32(0, hm.uri.buf, hm.uri.len); |
84 | 63.3k | for (size_t i = 0; i < sizeof(hm.headers) / sizeof(hm.headers[0]); i++) { |
85 | 61.2k | struct mg_str *k = &hm.headers[i].name, *v = &hm.headers[i].value; |
86 | 61.2k | mg_crc32(0, k->buf, k->len); |
87 | 61.2k | mg_crc32(0, v->buf, v->len); |
88 | 61.2k | } |
89 | 2.04k | } |
90 | 5.57k | mg_http_parse(NULL, 0, &hm); |
91 | | |
92 | 5.57k | struct mg_str body = mg_str_n((const char *) data, size); |
93 | 5.57k | char tmp[256]; |
94 | 5.57k | mg_http_get_var(&body, "key", tmp, sizeof(tmp)); |
95 | 5.57k | mg_http_get_var(&body, "key", NULL, 0); |
96 | 5.57k | mg_url_decode((char *) data, size, tmp, sizeof(tmp), 1); |
97 | 5.57k | mg_url_decode((char *) data, size, tmp, 1, 1); |
98 | 5.57k | mg_url_decode(NULL, 0, tmp, 1, 1); |
99 | | |
100 | 5.57k | struct mg_mqtt_message mm; |
101 | 5.57k | if (mg_mqtt_parse(data, size, 0, &mm) == MQTT_OK) { |
102 | 2.24k | mg_crc32(0, mm.topic.buf, mm.topic.len); |
103 | 2.24k | mg_crc32(0, mm.data.buf, mm.data.len); |
104 | 2.24k | mg_crc32(0, mm.dgram.buf, mm.dgram.len); |
105 | 2.24k | } |
106 | 5.57k | mg_mqtt_parse(NULL, 0, 0, &mm); |
107 | 5.57k | if (mg_mqtt_parse(data, size, 5, &mm) == MQTT_OK) { |
108 | 2.10k | mg_crc32(0, mm.topic.buf, mm.topic.len); |
109 | 2.10k | mg_crc32(0, mm.data.buf, mm.data.len); |
110 | 2.10k | mg_crc32(0, mm.dgram.buf, mm.dgram.len); |
111 | 2.10k | { |
112 | 2.10k | struct mg_mqtt_prop prop; |
113 | 2.10k | size_t ofs = 0; |
114 | 7.47k | while ((ofs = mg_mqtt_next_prop(&mm, &prop, ofs)) > 0) { |
115 | 5.37k | mg_crc32(0, prop.key.buf, prop.key.len); |
116 | 5.37k | mg_crc32(0, prop.val.buf, prop.val.len); |
117 | 5.37k | } |
118 | 2.10k | } |
119 | 2.10k | } |
120 | 5.57k | mg_mqtt_parse(NULL, 0, 5, &mm); |
121 | | |
122 | 5.57k | mg_sntp_parse(data, size); |
123 | 5.57k | mg_sntp_parse(NULL, 0); |
124 | | |
125 | 5.57k | char buf[size * 4 / 3 + 5]; // At least 4 chars and nul termination |
126 | 5.57k | mg_base64_decode((char *) data, size, buf, sizeof(buf)); |
127 | 5.57k | mg_base64_decode(NULL, 0, buf, sizeof(buf)); |
128 | 5.57k | mg_base64_encode(data, size, buf, sizeof(buf)); |
129 | 5.57k | mg_base64_encode(NULL, 0, buf, sizeof(buf)); |
130 | | |
131 | 5.57k | mg_match(mg_str_n((char *) data, size), mg_str_n((char *) data, size), NULL); |
132 | | |
133 | 5.57k | struct mg_str entry, s = mg_str_n((char *) data, size); |
134 | 1.08M | while (mg_span(s, &entry, &s, ',')) entry.len = 0; |
135 | | |
136 | 5.57k | int n; |
137 | 5.57k | mg_json_get(mg_str_n((char *) data, size), "$", &n); |
138 | 5.57k | mg_json_get(mg_str_n((char *) data, size), "$.a.b", &n); |
139 | 5.57k | mg_json_get(mg_str_n((char *) data, size), "$[0]", &n); |
140 | | |
141 | | // Test built-in TCP/IP stack |
142 | 5.57k | if (size > 0) { |
143 | 5.57k | static size_t t; |
144 | 5.57k | struct mg_tcpip_if mif = {.ip = 1, |
145 | 5.57k | .mask = 255, |
146 | 5.57k | .gw = 1, |
147 | 5.57k | .gw_ready = true, |
148 | 5.57k | .state = MG_TCPIP_STATE_READY, |
149 | | #if MG_ENABLE_IPV6 |
150 | | .ip6[0] = 1, |
151 | | .prefix[0] = 1, |
152 | | .prefix_len = 64, |
153 | | .gw6[0] = 1, |
154 | | .gw6_ready = true, |
155 | | .state6 = MG_TCPIP_STATE_READY, // so mg_send() works and RS stops |
156 | | #endif |
157 | 5.57k | .driver = &mg_tcpip_driver_mock}; |
158 | 5.57k | struct mg_mgr mgr; |
159 | | |
160 | 5.57k | if (t >= MG_TCPIP_L2_USER) t = 0; // defined in l2.h |
161 | 5.57k | mif.l2type = (enum mg_l2type) t++; // configure to a L2 type |
162 | | |
163 | 5.57k | mg_mgr_init(&mgr); |
164 | 5.57k | mg_tcpip_init(&mgr, &mif); |
165 | | |
166 | | // Make a copy of the random data, in order to modify it |
167 | 5.57k | void *pkt = malloc(size); |
168 | 5.57k | struct eth *eth = (struct eth *) pkt; |
169 | 5.57k | memcpy(pkt, data, size); |
170 | 5.57k | if ((mif.l2type == MG_TCPIP_L2_ETH || mif.l2type == MG_TCPIP_L2_PPPoE) && size > sizeof(*eth)) { |
171 | 2.65k | static size_t i, v; |
172 | 2.65k | static struct fuzz_l3_state l3; |
173 | 2.65k | uint8_t *ethpay = (uint8_t *) (eth + 1); |
174 | 2.65k | size_t ethhdrsz = sizeof(*eth); |
175 | 2.65k | uint16_t etype; |
176 | | // eth_types[] exists in l2_eth.c |
177 | 2.65k | memcpy(eth->dst, mif.mac, 6); // Set valid destination MAC |
178 | | // send all handled eth types, then 2 random ones |
179 | 2.65k | if (i >= (sizeof(eth_types) / sizeof(eth_types[0]) + 2)) i = 0; |
180 | 2.65k | if (i < (sizeof(eth_types) / sizeof(eth_types[0]))) eth->type = mg_htons(eth_types[i++]); |
181 | 2.65k | etype = mg_ntohs(eth->type); |
182 | 2.65k | if (v >= 10) v = 0; // 802.1Q tag 3 out of 10 frames |
183 | 2.65k | if (v < 3) mif.l2data.eth.vlan_id = 123; |
184 | 2.65k | if (size > sizeof(*eth) + sizeof(struct qtag)) { |
185 | 2.41k | struct qtag *qtag = (struct qtag *) ð->type; |
186 | 2.41k | if (v == 0) { |
187 | | // v=0: configured for VLAN 123, untagged frame, discard path |
188 | 2.17k | } else if (v == 1) { |
189 | | // v=1: configured for VLAN 123, tagged VLAN 123, accept path |
190 | 242 | qtag->tpid = mg_htons(0x8100); |
191 | 242 | qtag->tci = mg_htons(123); |
192 | 242 | MG_STORE_BE16(qtag + 1, etype); |
193 | 242 | ethhdrsz += sizeof(*qtag); |
194 | 242 | ethpay += sizeof(*qtag); |
195 | 1.92k | } else if (v == 2) { |
196 | | // v=2: configured for VLAN 123, tagged random VLAN, mismatch path |
197 | 242 | qtag->tpid = mg_htons(0x8100); |
198 | 242 | MG_STORE_BE16(qtag + 1, etype); |
199 | 242 | ethhdrsz += sizeof(*qtag); |
200 | 242 | ethpay += sizeof(*qtag); |
201 | 1.68k | } else if (v == 3) { |
202 | | // v=3: unconfigured VLAN, tagged frame, discard path |
203 | 241 | qtag->tpid = mg_htons(0x8100); |
204 | 241 | MG_STORE_BE16(qtag + 1, etype); |
205 | 241 | ethhdrsz += sizeof(*qtag); |
206 | 241 | ethpay += sizeof(*qtag); |
207 | 241 | } // else unconfigured VLAN, untagged frame, normal path |
208 | 2.41k | } |
209 | 2.65k | ++v; |
210 | 2.65k | if (etype == 0x8863 && size > (ethhdrsz + sizeof(struct pppoe))) { // PPPoE disc |
211 | 58 | static size_t j; |
212 | 58 | uint8_t pppoe_codes[] = {MG_PPPoE_PADO, MG_PPPoE_PADS, MG_PPPoE_PADT}; // defined in l2_ppp.c |
213 | 58 | struct pppoe *pppoe = (struct pppoe *) ethpay; |
214 | 58 | pppoe->vertype = 0x11; |
215 | | // send all handled PPPoE codes, then 2 random ones |
216 | 58 | if (j >= (sizeof(pppoe_codes) / sizeof(pppoe_codes[0]) + 2)) j = 0; |
217 | 58 | if (j < (sizeof(pppoe_codes) / sizeof(pppoe_codes[0]))) pppoe->code = (pppoe_codes[j++]); |
218 | 58 | if (pppoe->code == MG_PPPoE_PADO) { |
219 | 4 | static size_t k; |
220 | | // send id=0, then 2 random ids |
221 | 4 | if (k >= 3) k = 0; |
222 | 4 | if (k == 0) pppoe->id = 0; |
223 | 4 | ++k; |
224 | 54 | } else if (pppoe->code == MG_PPPoE_PADS) { |
225 | 7 | static size_t k; |
226 | | // send id=x, then 2 random ids |
227 | 7 | if (k >= 3) k = 0; |
228 | 7 | if (k == 0) pppoe->id = 0x1234; |
229 | 7 | ++k; |
230 | 47 | } else if (pppoe->code == MG_PPPoE_PADT) { // keep separate so they do not correlate too much |
231 | 10 | static size_t k; |
232 | | // send id=x, then 2 random ids |
233 | 10 | if (k >= 3) k = 0; |
234 | 10 | if (k == 0) pppoe->id = 0x1234; |
235 | 10 | ++k; |
236 | 10 | } |
237 | 2.59k | } else if (etype == 0x8864 && size > (ethhdrsz + sizeof(struct pppoe))) { // PPPoE sess |
238 | | // PPP rx is covered via HDLC too; PPPoE tx wrapping may remain unexercised. |
239 | 41 | struct pppoe *pppoe = (struct pppoe *) ethpay; |
240 | 41 | static size_t k, l; |
241 | | // send code=0, then 2 random codes |
242 | 41 | if (k >= 3) k = 0; |
243 | 41 | if (k == 0) { |
244 | 14 | static size_t m; |
245 | 14 | pppoe->code = 0; |
246 | | // send id=x, then 2 random ids |
247 | 14 | if (m >= 3) m = 0; |
248 | 14 | if (m == 0) pppoe->id = 0x1234; |
249 | 14 | ++m; |
250 | 14 | } |
251 | 41 | ++k; |
252 | | // set s_state to valid and invalid |
253 | 41 | if (l >= 2) l = 0; |
254 | 41 | if (l == 0) s_state = MG_PPPoE_ST_SESS; // defined in l2_ppp.c |
255 | 41 | if (l == 1) s_state = MG_PPPoE_ST_REQ; |
256 | 41 | ++l; |
257 | | // PPP exercised in other block |
258 | 41 | } |
259 | | // build proper layer-3 datagrams, to be able to exercise layers above |
260 | 2.55k | else if (etype == 0x800 && size > (ethhdrsz + sizeof(struct ip))) { // IPv4 |
261 | 109 | fuzz_ip4(ethpay, size - ethhdrsz, &l3); |
262 | 2.44k | } else if (etype == 0x806) { // ARP |
263 | | |
264 | 2.39k | } else if (etype == 0x86dd && size > (ethhdrsz + sizeof(struct ip6))) { // IPv6 |
265 | 21 | fuzz_ip6(ethpay, size - ethhdrsz, &l3); |
266 | 21 | } |
267 | 2.92k | } else if (mif.l2type == MG_TCPIP_L2_PPP && size > (sizeof(struct hdlc_) + sizeof(struct ppp) + 2)) { |
268 | 1.56k | static size_t i; |
269 | 1.56k | static struct fuzz_l3_state l3; |
270 | 1.56k | uint16_t ppp_protos[] = { |
271 | 1.56k | MG_PPP_PROTO_LCP, MG_PPP_PROTO_IPCP, MG_PPP_PROTO_IP, MG_PPP_PROTO_IPV6CP, MG_PPP_PROTO_IPV6 |
272 | 1.56k | }; |
273 | 1.56k | struct hdlc_ *hdlc = (struct hdlc_ *) pkt; |
274 | 1.56k | struct ppp *ppp = (struct ppp *) (hdlc + 1); |
275 | 1.56k | size_t len = size - sizeof(*hdlc) - sizeof(*ppp) - 2; |
276 | 1.56k | hdlc->addr = MG_PPP_ADDR; |
277 | 1.56k | hdlc->ctrl = MG_PPP_CTRL; |
278 | 1.56k | s_lcpup = true; |
279 | | // send all handled PPP protocols, then 2 random ones |
280 | 1.56k | if (i >= (sizeof(ppp_protos) / sizeof(ppp_protos[0]) + 2)) i = 0; |
281 | 1.56k | if (i < (sizeof(ppp_protos) / sizeof(ppp_protos[0]))) ppp->proto = mg_htons(ppp_protos[i++]); |
282 | 1.56k | if (ppp->proto == mg_htons(MG_PPP_PROTO_LCP) && len >= sizeof(struct lcp)) { |
283 | 40 | static size_t j, k; |
284 | 40 | uint8_t lcp_codes[] = {MG_PPP_LCP_CFG_REQ, MG_PPP_LCP_CFG_ACK, MG_PPP_LCP_CFG_TERM_REQ, MG_PPP_LCP_ECHO_REQ}; |
285 | 40 | struct lcp *lcp = (struct lcp *) (ppp + 1); |
286 | | // send all handled LCP codes, then 2 random ones |
287 | 40 | if (j >= (sizeof(lcp_codes) / sizeof(lcp_codes[0]) + 2)) j = 0; |
288 | 40 | if (j < (sizeof(lcp_codes) / sizeof(lcp_codes[0]))) lcp->code = lcp_codes[j++]; |
289 | | // send valid length, then 2 random lengths |
290 | 40 | if (k >= 3) k = 0; |
291 | 40 | if (k == 0) lcp->len = mg_htons((uint16_t) sizeof(*lcp)); |
292 | 40 | ++k; |
293 | 1.52k | } else if (ppp->proto == mg_htons(MG_PPP_PROTO_IPCP) && len >= 10) { |
294 | 27 | static size_t j, k, m; |
295 | 27 | uint8_t ipcp_codes[] = {MG_PPP_IPCP_CFG_REQ, MG_PPP_IPCP_CFG_ACK, MG_PPP_IPCP_CFG_NACK, MG_PPP_IPCP_CFG_REJECT}; |
296 | 27 | struct ipcp *ipcp = (struct ipcp *) (ppp + 1); |
297 | 27 | uint8_t *opts = (uint8_t *) (ipcp + 1); |
298 | | // send all handled IPCP codes, then 2 random ones |
299 | 27 | if (j >= (sizeof(ipcp_codes) / sizeof(ipcp_codes[0]) + 2)) j = 0; |
300 | 27 | if (j < (sizeof(ipcp_codes) / sizeof(ipcp_codes[0]))) ipcp->code = ipcp_codes[j++]; |
301 | | // send valid length, then 2 random lengths |
302 | 27 | if (m >= 3) m = 0; |
303 | 27 | if (m == 0) ipcp->len = mg_htons(10); |
304 | 27 | ++m; |
305 | | // send valid IPADDR option, then 2 random option types |
306 | 27 | if (k >= 3) k = 0; |
307 | 27 | if (k == 0) { |
308 | 9 | static size_t l; |
309 | 9 | opts[0] = MG_PPP_IPCP_OPT_IPADDR; |
310 | | // for valid option type, send valid length, then random length |
311 | 9 | if (l >= 2) l = 0; |
312 | 9 | if (l == 0) opts[1] = 6; |
313 | 9 | ++l; |
314 | 9 | } |
315 | 27 | ++k; |
316 | 1.50k | } else if (ppp->proto == mg_htons(MG_PPP_PROTO_IP) && len >= sizeof(struct ip)) { |
317 | 31 | fuzz_ip4(ppp + 1, len, &l3); |
318 | 1.47k | } else if (ppp->proto == mg_htons(MG_PPP_PROTO_IPV6CP) && len >= 14) { |
319 | 19 | static size_t j, k, m; |
320 | 19 | uint8_t ipv6cp_codes[] = {MG_PPP_IPV6CP_CFG_REQ, MG_PPP_IPV6CP_CFG_ACK, MG_PPP_IPV6CP_CFG_NACK, MG_PPP_IPV6CP_CFG_REJECT}; |
321 | 19 | struct ipv6cp *ipv6cp = (struct ipv6cp *) (ppp + 1); |
322 | 19 | uint8_t *opts = (uint8_t *) (ipv6cp + 1); |
323 | | // send all handled IPV6CP codes, then 2 random ones |
324 | 19 | if (j >= (sizeof(ipv6cp_codes) / sizeof(ipv6cp_codes[0]) + 2)) j = 0; |
325 | 19 | if (j < (sizeof(ipv6cp_codes) / sizeof(ipv6cp_codes[0]))) ipv6cp->code = ipv6cp_codes[j++]; |
326 | | // send valid length, then 2 random lengths |
327 | 19 | if (m >= 3) m = 0; |
328 | 19 | if (m == 0) ipv6cp->len = mg_htons(14); |
329 | 19 | ++m; |
330 | | // send valid IFCID option, then 2 random option types |
331 | 19 | if (k >= 3) k = 0; |
332 | 19 | if (k == 0) { |
333 | 7 | static size_t l; |
334 | 7 | opts[0] = MG_PPP_IPV6CP_OPT_IFCID; |
335 | | // for valid option type, send valid length, then random length |
336 | 7 | if (l >= 2) l = 0; |
337 | 7 | if (l == 0) { |
338 | 4 | static size_t o; |
339 | 4 | opts[1] = 10; |
340 | | // for valid option length, send non-zero IFCID, then 2 random IFCIDs |
341 | 4 | if (o >= 3) o = 0; |
342 | 4 | if (o == 0) opts[9] = 1; |
343 | 4 | ++o; |
344 | 4 | } |
345 | 7 | ++l; |
346 | 7 | } |
347 | 19 | ++k; |
348 | 1.45k | } else if (ppp->proto == mg_htons(MG_PPP_PROTO_IPV6) && len >= sizeof(struct ip6)) { |
349 | 46 | fuzz_ip6(ppp + 1, len, &l3); |
350 | 46 | } |
351 | 1.56k | } |
352 | | |
353 | | #if defined(MAIN) |
354 | | printf("Sending to net_builtin:\n"); |
355 | | mg_hexdump(pkt, size); |
356 | | #endif |
357 | 5.57k | mg_tcpip_rx(&mif, pkt, size); |
358 | | |
359 | | // prior actions may have had consequences on link state |
360 | 5.57k | mif.state = MG_TCPIP_STATE_READY; |
361 | | // Test HTTP serving (via our built-in TCP/IP stack) |
362 | 5.57k | const char *url = "http://localhost:12345"; // internally resolves |
363 | | // creates a connection and sends SYN via the router, unless OOM |
364 | 5.57k | struct mg_connection *c = mg_http_connect(&mgr, url, fn, NULL); |
365 | 5.57k | mg_iobuf_add(&c->recv, 0, data, size); |
366 | 5.57k | c->pfn(c, MG_EV_READ, NULL); // manually invoke protocol event handler |
367 | | |
368 | 5.57k | free(pkt); |
369 | 5.57k | mg_mgr_free(&mgr); |
370 | 5.57k | } |
371 | | |
372 | 5.57k | return 0; |
373 | 5.57k | } |
374 | | |
375 | | #if defined(MAIN) |
376 | | int main(int argc, char *argv[]) { |
377 | | int res = EXIT_FAILURE; |
378 | | if (argc > 1) { |
379 | | struct mg_str data = mg_file_read(&mg_fs_posix, argv[1]); |
380 | | if (data.buf != NULL) { |
381 | | LLVMFuzzerTestOneInput((uint8_t *) data.buf, data.len); |
382 | | res = EXIT_SUCCESS; |
383 | | } |
384 | | free(data.buf); |
385 | | } |
386 | | return res; |
387 | | } |
388 | | #endif |