Coverage Report

Created: 2026-08-14 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/SockFuzzer/fuzz/net_fuzzer.cc
Line
Count
Source
1
/*
2
 * Copyright 2021 Google LLC
3
 *
4
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5
 *
6
 * This file contains Original Code and/or Modifications of Original Code
7
 * as defined in and that are subject to the Apple Public Source License
8
 * Version 2.0 (the 'License'). You may not use this file except in
9
 * compliance with the License. The rights granted to you under the License
10
 * may not be used to create, or enable the creation or redistribution of,
11
 * unlawful or unlicensed copies of an Apple operating system, or to
12
 * circumvent, violate, or enable the circumvention or violation of, any
13
 * terms of an Apple operating system software license agreement.
14
 *
15
 * Please obtain a copy of the License at
16
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17
 *
18
 * The Original Code and all software distributed under the License are
19
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23
 * Please see the License for the specific language governing rights and
24
 * limitations under the License.
25
 *
26
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27
 */
28
29
#include <fuzzer/FuzzedDataProvider.h>
30
#include <stddef.h>
31
#include <stdint.h>
32
#include <string.h>
33
34
#include <iostream>
35
#include <memory>
36
#include <vector>
37
38
#include "net_fuzzer.pb.h"
39
#include "src/libfuzzer/libfuzzer_macro.h"
40
41
extern "C" {
42
#include "api/backend.h"
43
#include "api/syscall_wrappers.h"
44
#include "types.h"
45
}
46
47
/*
48
TODO(nedwill)
49
50
Fuzz vsock domain
51
*/
52
53
// TODO(nedwill): support multiple addresses of each type below,
54
// not just one of each type
55
523k
void get_in6_addr(struct in6_addr *sai, enum In6Addr addr) {
56
523k
  memset(sai, 0, sizeof(*sai));
57
523k
  switch (addr) {
58
4.66k
    case IN6_ADDR_SELF: {
59
4.66k
      sai->__u6_addr.__u6_addr32[0] = 16810238;
60
4.66k
      sai->__u6_addr.__u6_addr32[0] = 0;
61
4.66k
      sai->__u6_addr.__u6_addr32[0] = 0;
62
4.66k
      sai->__u6_addr.__u6_addr32[0] = 16777216;
63
      // assert(IN6_IS_ADDR_SELF(sai));
64
4.66k
      break;
65
0
    }
66
2.18k
    case IN6_ADDR_LINK_LOCAL: {
67
2.18k
      sai->s6_addr[0] = 0xfe;
68
2.18k
      sai->s6_addr[1] = 0x80;
69
      // TODO(nedwill): set other fields?
70
2.18k
      assert(IN6_IS_ADDR_LINKLOCAL(sai));
71
2.18k
      break;
72
2.18k
    }
73
248k
    case IN6_ADDR_LOOPBACK: {
74
248k
      *sai = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (uint8_t)addr};
75
248k
      assert(IN6_IS_ADDR_LOOPBACK(sai));
76
248k
      break;
77
248k
    }
78
248k
    case IN6_ADDR_REAL:
79
7.07k
    case MAYBE_LOCALHOST: {
80
7.07k
      *sai = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (uint8_t)addr};
81
7.07k
      break;
82
6.83k
    }
83
2.85k
    case IN6_ADDR_V4COMPAT: {
84
2.85k
      sai->s6_addr[12] = 1;
85
2.85k
      assert(IN6_IS_ADDR_V4COMPAT(sai));
86
2.85k
      break;
87
2.85k
    }
88
28.5k
    case IN6_ADDR_V4MAPPED: {
89
28.5k
      *(uint32_t *)&sai->s6_addr[8] = 0xffff0000;
90
28.5k
      assert(IN6_IS_ADDR_V4MAPPED(sai));
91
28.5k
      break;
92
28.5k
    }
93
28.5k
    case IN6_ADDR_6TO4: {
94
888
      sai->s6_addr16[0] = ntohs(0x2002);
95
888
      assert(IN6_IS_ADDR_6TO4(sai));
96
888
      break;
97
888
    }
98
3.59k
    case IN6_ADDR_LINKLOCAL: {
99
3.59k
      sai->s6_addr[0] = 0xfe;
100
3.59k
      sai->s6_addr[1] = 0x80;
101
3.59k
      assert(IN6_IS_ADDR_LINKLOCAL(sai));
102
3.59k
      break;
103
3.59k
    }
104
3.59k
    case IN6_ADDR_SITELOCAL: {
105
603
      sai->s6_addr[0] = 0xfe;
106
603
      sai->s6_addr[1] = 0xc0;
107
603
      assert(IN6_IS_ADDR_SITELOCAL(sai));
108
603
      break;
109
603
    }
110
1.65k
    case IN6_ADDR_MULTICAST: {
111
1.65k
      sai->s6_addr[0] = 0xff;
112
1.65k
      assert(IN6_IS_ADDR_MULTICAST(sai));
113
1.65k
      break;
114
1.65k
    }
115
1.65k
    case IN6_ADDR_UNIQUE_LOCAL: {
116
1.11k
      sai->s6_addr[0] = 0xfc;
117
1.11k
      assert(IN6_IS_ADDR_UNIQUE_LOCAL(sai));
118
1.11k
      break;
119
1.11k
    }
120
1.61k
    case IN6_ADDR_MC_NODELOCAL: {
121
1.61k
      sai->s6_addr[0] = 0xff;
122
1.61k
      sai->s6_addr[1] = __IPV6_ADDR_SCOPE_NODELOCAL;
123
1.61k
      assert(IN6_IS_ADDR_MC_NODELOCAL(sai));
124
1.61k
      break;
125
1.61k
    }
126
1.61k
    case IN6_ADDR_MC_INTFACELOCAL: {
127
471
      sai->s6_addr[0] = 0xff;
128
471
      sai->s6_addr[1] = __IPV6_ADDR_SCOPE_INTFACELOCAL;
129
471
      assert(IN6_IS_ADDR_MC_INTFACELOCAL(sai));
130
471
      break;
131
471
    }
132
8.29k
    case IN6_ADDR_MC_LINKLOCAL: {
133
8.29k
      sai->s6_addr[0] = 0xff;
134
8.29k
      sai->s6_addr[1] = __IPV6_ADDR_SCOPE_LINKLOCAL;
135
8.29k
      assert(IN6_IS_ADDR_MC_LINKLOCAL(sai));
136
8.29k
      break;
137
8.29k
    }
138
8.29k
    case IN6_ADDR_MC_SITELOCAL: {
139
2.22k
      sai->s6_addr[0] = 0xff;
140
2.22k
      sai->s6_addr[1] = __IPV6_ADDR_SCOPE_SITELOCAL;
141
2.22k
      assert(IN6_IS_ADDR_MC_SITELOCAL(sai));
142
2.22k
      break;
143
2.22k
    }
144
2.22k
    case IN6_ADDR_MC_ORGLOCAL: {
145
1.81k
      sai->s6_addr[0] = 0xff;
146
1.81k
      sai->s6_addr[1] = __IPV6_ADDR_SCOPE_ORGLOCAL;
147
1.81k
      assert(IN6_IS_ADDR_MC_ORGLOCAL(sai));
148
1.81k
      break;
149
1.81k
    }
150
1.81k
    case IN6_ADDR_MC_GLOBAL: {
151
901
      sai->s6_addr[0] = 0xff;
152
901
      sai->s6_addr[1] = __IPV6_ADDR_SCOPE_GLOBAL;
153
901
      assert(IN6_IS_ADDR_MC_GLOBAL(sai));
154
901
      break;
155
901
    }
156
7.95k
    case IN6_ADDR_UNSPECIFIED:
157
204k
    case IN6_ADDR_ANY: {
158
204k
      assert(IN6_IS_ADDR_UNSPECIFIED(sai));
159
204k
      break;
160
204k
    }
161
204k
    case IN6_ADDR_LOCAL_ADDRESS: {
162
      // Discovered this address dynamically
163
      // fe80:0001:0000:0000:a8aa:aaaa:aaaa:aaaa
164
1.17k
      sai->s6_addr16[0] = 0xfe80;
165
1.17k
      sai->s6_addr16[1] = 0x0001;
166
1.17k
      sai->s6_addr16[4] = 0xa8aa;
167
1.17k
      sai->s6_addr16[5] = 0xaaaa;
168
1.17k
      sai->s6_addr16[6] = 0xaaaa;
169
1.17k
      sai->s6_addr16[7] = 0xaaaa;
170
1.17k
    }
171
      // *sai = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (uint8_t)addr};
172
523k
  }
173
523k
}
174
175
81.1k
void get_sockaddr6(struct sockaddr_in6 *sai, const SockAddr6 &sa6) {
176
81.1k
  sai->sin6_len = sizeof(struct sockaddr_in6);
177
81.1k
  sai->sin6_family = (sa_family_t)AF_INET6;  // sa6.family();
178
81.1k
  sai->sin6_port = (in_port_t)sa6.port();
179
81.1k
  sai->sin6_flowinfo = sa6.flow_info();
180
81.1k
  get_in6_addr(&sai->sin6_addr, sa6.sin6_addr());
181
81.1k
  sai->sin6_scope_id = sa6.sin6_scope_id();
182
81.1k
}
183
184
1.02M
std::string get_sockaddr(const SockAddr &sockaddr) {
185
1.02M
  std::string dat;
186
1.02M
  switch (sockaddr.sockaddr_case()) {
187
81.1k
    case SockAddr::kSockaddrGeneric: {
188
81.1k
      const SockAddrGeneric &sag = sockaddr.sockaddr_generic();
189
      // data size + sizeof(sa_len) + sizeof(sa_family)
190
81.1k
      struct sockaddr_generic sag_s = {
191
81.1k
          .sa_len = (uint8_t)(sizeof(sockaddr_generic) + sag.sa_data().size()),
192
81.1k
          .sa_family = (uint8_t)sag.sa_family(),
193
81.1k
      };
194
195
81.1k
      dat = std::string((char *)&sag_s, (char *)&sag_s + sizeof(sag_s));
196
81.1k
      dat += sag.sa_data();
197
81.1k
      break;
198
0
    }
199
57.0k
    case SockAddr::kSockaddr4: {
200
57.0k
      struct sockaddr_in sai = {
201
57.0k
          .sin_len = sizeof(struct sockaddr_in),
202
57.0k
          .sin_family =
203
57.0k
              AF_INET,  // (unsigned char)sockaddr.sockaddr4().sin_family(),
204
57.0k
          .sin_port = (unsigned short)sockaddr.sockaddr4().sin_port(),
205
57.0k
          .sin_addr = {(unsigned int)sockaddr.sockaddr4().sin_addr()},
206
57.0k
          .sin_zero = {},
207
57.0k
      };
208
57.0k
      dat = std::string((char *)&sai, (char *)&sai + sizeof(sai));
209
57.0k
      break;
210
0
    }
211
37.9k
    case SockAddr::kSockaddr6: {
212
37.9k
      struct sockaddr_in6 sai = {};
213
37.9k
      get_sockaddr6(&sai, sockaddr.sockaddr6());
214
37.9k
      dat = std::string((char *)&sai, (char *)&sai + sizeof(sai));
215
37.9k
      break;
216
0
    }
217
    // case SockAddr::kRawBytes: {
218
    //   dat = sockaddr.raw_bytes();
219
    //   break;
220
    // }
221
852k
    case SockAddr::SOCKADDR_NOT_SET: {
222
852k
      break;
223
0
    }
224
1.02M
  }
225
1.02M
  return dat;
226
1.02M
}
227
228
221k
std::string get_ip6_hdr(const Ip6Hdr &hdr, uint16_t expected_size) {
229
221k
  struct ip6_hdr ip6_hdr;
230
221k
  memset(&ip6_hdr, 0, sizeof(ip6_hdr));
231
221k
  get_in6_addr(&ip6_hdr.ip6_src, hdr.ip6_src());
232
221k
  get_in6_addr(&ip6_hdr.ip6_dst, hdr.ip6_src());
233
221k
  ip6_hdr.ip6_ctlun.ip6_un2_vfc = IPV6_VERSION;
234
  // How TF does flow work?
235
  // ip6_hdr.ip6_ctlun.ip6_un1.ip6_un1_flow = hdr.ip6_hdrctl().ip6_un1_flow();
236
221k
  ip6_hdr.ip6_ctlun.ip6_un1.ip6_un1_plen =
237
221k
      __builtin_bswap16(expected_size);  // hdr.ip6_hdrctl().ip6_un1_plen();
238
221k
  ip6_hdr.ip6_ctlun.ip6_un1.ip6_un1_nxt = hdr.ip6_hdrctl().ip6_un1_nxt();
239
221k
  ip6_hdr.ip6_ctlun.ip6_un1.ip6_un1_hlim = hdr.ip6_hdrctl().ip6_un1_hlim();
240
221k
  std::string dat((char *)&ip6_hdr, (char *)&ip6_hdr + sizeof(ip6_hdr));
241
221k
  return dat;
242
221k
}
243
244
151k
std::string get_ip_hdr(const IpHdr &hdr, size_t expected_size) {
245
151k
  struct in_addr ip_src = {.s_addr = (unsigned int)hdr.ip_src()};
246
151k
  struct in_addr ip_dst = {.s_addr = (unsigned int)hdr.ip_dst()};
247
151k
  struct ip ip_hdr = {
248
151k
      .ip_hl = 5,    // TODO(nedwill): support options // hdr.ip_hl(),
249
151k
      .ip_v = IPV4,  // hdr.ip_v(),
250
151k
      .ip_tos = (u_char)hdr.ip_tos(),
251
151k
      .ip_len = (u_short)__builtin_bswap16(expected_size),
252
151k
      .ip_id = (u_short)hdr.ip_id(),
253
151k
      .ip_off = (u_short)hdr.ip_off(),
254
151k
      .ip_ttl = (u_char)hdr.ip_ttl(),
255
151k
      .ip_p = (u_char)hdr.ip_p(),
256
151k
      .ip_sum = 0,
257
151k
      .ip_src = ip_src,
258
151k
      .ip_dst = ip_dst,
259
151k
  };
260
151k
  std::string dat((char *)&ip_hdr, (char *)&ip_hdr + sizeof(ip_hdr));
261
151k
  return dat;
262
151k
}
263
264
// message TcpHdr {
265
//   required Port th_sport = 1;
266
//   required Port th_dport = 2;
267
//   required uint32 th_seq = 3;
268
//   required uint32 th_ack = 4;
269
//   required uint32 th_off = 5;
270
//   repeated TcpFlag th_flags = 6;
271
//   required uint32 th_win = 7;
272
//   required uint32 th_sum = 8;
273
//   required uint32 th_urp = 9;
274
// }
275
276
52.5k
std::string get_tcp_hdr(const TcpHdr &hdr) {
277
52.5k
  struct tcphdr tcphdr = {
278
52.5k
      .th_sport = (unsigned short)hdr.th_sport(),
279
52.5k
      .th_dport = (unsigned short)hdr.th_dport(),
280
52.5k
      .th_seq = __builtin_bswap32(hdr.th_seq()),
281
52.5k
      .th_ack = __builtin_bswap32(hdr.th_ack()),
282
52.5k
      .th_off = hdr.th_off(),
283
52.5k
      .th_flags = 0,
284
52.5k
      .th_win = (unsigned short)hdr.th_win(),
285
52.5k
      .th_sum = 0,
286
52.5k
      .th_urp = (unsigned short)hdr.th_urp(),
287
52.5k
  };
288
289
52.5k
  for (const int flag : hdr.th_flags()) {
290
15.4k
    tcphdr.th_flags ^= flag;
291
15.4k
  }
292
293
  // Prefer pure syn
294
52.5k
  if (hdr.is_pure_syn()) {
295
3.85k
    tcphdr.th_flags &= ~(TH_RST | TH_ACK);
296
3.85k
    tcphdr.th_flags |= TH_SYN;
297
48.7k
  } else if (hdr.is_pure_ack()) {
298
3.29k
    tcphdr.th_flags &= ~(TH_RST | TH_SYN);
299
3.29k
    tcphdr.th_flags |= TH_ACK;
300
3.29k
  }
301
302
52.5k
  std::string dat((char *)&tcphdr, (char *)&tcphdr + sizeof(tcphdr));
303
52.5k
  return dat;
304
52.5k
}
305
306
0
std::string get_icmp6_hdr(const Icmp6Hdr &hdr) {
307
0
  struct icmp6_hdr icmp6_hdr = {
308
0
      .icmp6_type = (uint8_t)hdr.icmp6_type(),
309
0
      .icmp6_code = (uint8_t)hdr.icmp6_code(),
310
0
      .icmp6_cksum = 0,
311
0
  };
312
0
  icmp6_hdr.icmp6_dataun.icmp6_un_data32[0] = hdr.icmp6_dataun();
313
314
0
  std::string dat((char *)&icmp6_hdr, (char *)&icmp6_hdr + sizeof(icmp6_hdr));
315
0
  return dat;
316
0
}
317
318
0
std::string get_ip6_route_hdr(const Ip6RtHdr &hdr) {
319
0
  struct ip6_rthdr ip6_rthdr = {
320
0
      .ip6r_nxt = (uint8_t)hdr.ip6r_nxt(),
321
0
      .ip6r_len = (uint8_t)hdr.ip6r_len(),
322
0
      .ip6r_type = (uint8_t)hdr.ip6r_type(),
323
0
      .ip6r_segleft = (uint8_t)hdr.ip6r_segleft(),
324
0
  };
325
326
0
  std::string dat((char *)&ip6_rthdr, (char *)&ip6_rthdr + sizeof(ip6_rthdr));
327
0
  return dat;
328
0
}
329
330
0
std::string get_ip6_route0_hdr(const Ip6Rt0Hdr &hdr) {
331
0
  struct ip6_rthdr0 ip6_rthdr0 = {};
332
0
  ip6_rthdr0.ip6r0_nxt = hdr.ip6r0_nxt();
333
0
  ip6_rthdr0.ip6r0_len = hdr.ip6r0_len();
334
0
  ip6_rthdr0.ip6r0_type = hdr.ip6r0_type();
335
0
  ip6_rthdr0.ip6r0_segleft = hdr.ip6r0_segleft();
336
0
  ip6_rthdr0.ip6r0_reserved = hdr.ip6r0_reserved();
337
0
  *(uint32_t *)&ip6_rthdr0.ip6r0_slmap[0] = hdr.ip6r0_slmap();
338
339
0
  int i = 0;
340
0
  for (int in6addr : hdr.ip6r0_addr()) {
341
0
    if (i >= 23) {
342
0
      break;
343
0
    }
344
345
0
    get_in6_addr(&ip6_rthdr0.ip6r0_addr[i], (In6Addr)in6addr);
346
347
0
    i++;
348
0
  }
349
350
0
  std::string dat((char *)&ip6_rthdr0,
351
0
                  (char *)&ip6_rthdr0 + sizeof(ip6_rthdr0));
352
0
  return dat;
353
0
}
354
355
0
std::string get_ip6_frag_hdr(const Ip6FragHdr &hdr) {
356
0
  struct ip6_frag ip6_frag = {
357
0
      .ip6f_nxt = (uint8_t)hdr.ip6f_nxt(),
358
0
      .ip6f_reserved = (uint8_t)hdr.ip6f_reserved(),
359
0
      .ip6f_offlg = (uint16_t)hdr.ip6f_offlg(),
360
0
      .ip6f_ident = hdr.ip6f_ident(),
361
0
  };
362
363
0
  std::string dat((char *)&ip6_frag, (char *)&ip6_frag + sizeof(ip6_frag));
364
0
  return dat;
365
0
}
366
367
0
std::string get_ip6_ext(const Ip6Ext &hdr) {
368
0
  struct ip6_ext ip6_ext = {
369
0
      .ip6e_nxt = (uint8_t)hdr.ip6e_nxt(),
370
0
      .ip6e_len = (uint8_t)hdr.ip6e_len(),
371
0
  };
372
373
0
  std::string dat((char *)&ip6_ext, (char *)&ip6_ext + sizeof(ip6_ext));
374
0
  return dat;
375
0
}
376
377
0
std::string GetNecpClient(const NecpClientId &necp_client_id) {
378
0
  switch (necp_client_id) {
379
0
    case CLIENT_0: {
380
0
      return "0000000000000000";
381
0
    }
382
0
    case CLIENT_1: {
383
0
      return "1111111111111111";
384
0
    }
385
0
    case CLIENT_2: {
386
0
      return "2222222222222222";
387
0
    }
388
0
  }
389
0
  assert(false);
390
0
  return "";
391
0
}
392
393
extern "C" {
394
395
static FuzzedDataProvider *fdp = nullptr;
396
397
// These are callbacks to let the C-based backend access the fuzzed input
398
// stream.
399
817k
void get_fuzzed_bytes(void *addr, size_t bytes) {
400
  // If we didn't initialize the fdp just clear the bytes.
401
817k
  if (!fdp) {
402
2
    memset(addr, 0, bytes);
403
2
    return;
404
2
  }
405
817k
  memset(addr, 0, bytes);
406
817k
  std::vector<uint8_t> dat = fdp->ConsumeBytes<uint8_t>(bytes);
407
817k
  memcpy(addr, dat.data(), dat.size());
408
817k
}
409
410
524k
bool get_fuzzed_bool(void) {
411
  // If we didn't initialize the fdp just return false.
412
524k
  if (!fdp) {
413
0
    return false;
414
0
  }
415
524k
  return fdp->ConsumeBool();
416
524k
}
417
418
0
int get_fuzzed_int32(int low, int high) {
419
0
  return fdp->ConsumeIntegralInRange<int>(low, high);
420
0
}
421
422
0
unsigned int get_fuzzed_uint32(unsigned int low, unsigned int high) {
423
0
  return fdp->ConsumeIntegralInRange<unsigned int>(low, high);
424
0
}
425
426
0
unsigned int get_remaining_bytes() { return fdp->remaining_bytes(); }
427
428
static bool ready = false;
429
430
bool initialize_network(void);
431
432
extern unsigned long ioctls[];
433
extern int num_ioctls;
434
extern const unsigned long siocaifaddr_in6_64;
435
extern const unsigned long siocsifflags;
436
437
// Enable this when copyout should work.
438
extern bool real_copyout;
439
440
void get_in6_addrlifetime_64(struct in6_addrlifetime_64 *sai,
441
14.3k
                             const In6AddrLifetime_64 &msg) {
442
14.3k
  sai->ia6t_expire = msg.ia6t_expire();
443
14.3k
  sai->ia6t_preferred = msg.ia6t_preferred();
444
14.3k
  sai->ia6t_vltime = msg.ia6t_vltime();
445
14.3k
  sai->ia6t_pltime = msg.ia6t_pltime();
446
14.3k
}
447
448
59.7k
void get_ifr_name(void *dest, const IfrName name) {
449
59.7k
  switch (name) {
450
59.7k
    case LO0: {
451
59.7k
      memcpy(dest, "lo0", sizeof("lo0"));
452
59.7k
      break;
453
0
    }
454
0
    case STF0: {
455
0
      memcpy(dest, "stf0", sizeof("stf0"));
456
0
      break;
457
0
    }
458
59.7k
  }
459
59.7k
}
460
461
// NECP client wrappers
462
// TODO(nedwill): move these to their own file
463
void necp_client_add(int fd, NecpClientId client_id, unsigned char *data,
464
0
                     size_t size) {
465
0
  std::string client_id_s = GetNecpClient(client_id);
466
0
  int retval = 0;
467
0
  necp_client_action_wrapper(fd, NECP_CLIENT_ACTION_ADD,
468
                             // parameters
469
0
                             (unsigned char *)client_id_s.data(),
470
0
                             client_id_s.size(), data, size, &retval);
471
0
}
472
473
// TODO(nedwill): support flow_ifnet_stats
474
0
void necp_client_remove(int fd, NecpClientId client_id) {
475
0
  std::string client_id_s = GetNecpClient(client_id);
476
0
  int retval = 0;
477
0
  necp_client_action_wrapper(fd, NECP_CLIENT_ACTION_REMOVE,
478
0
                             (unsigned char *)client_id_s.data(),
479
0
                             client_id_s.size(), nullptr, 0, &retval);
480
0
}
481
482
void necp_client_copy_parameters(int fd, NecpClientId client_id,
483
0
                                 uint32_t copyout_size) {
484
0
  std::string client_id_s = GetNecpClient(client_id);
485
0
  copyout_size %= 4096;
486
0
  std::unique_ptr<uint8_t[]> copyout_buffer(new uint8_t[copyout_size]);
487
0
  int retval = 0;
488
0
  necp_client_action_wrapper(fd, NECP_CLIENT_ACTION_COPY_PARAMETERS,
489
0
                             (unsigned char *)client_id_s.data(),
490
0
                             client_id_s.size(), copyout_buffer.get(),
491
0
                             copyout_size, &retval);
492
0
}
493
494
void necp_client_agent(
495
    int fd, NecpClientId client_id,
496
0
    const ::google::protobuf::RepeatedPtrField<::NecpTlv> &necp_tlv) {
497
0
  std::string client_id_s = GetNecpClient(client_id);
498
0
  std::string parameters;
499
0
  for (const NecpTlv &tlv : necp_tlv) {
500
    // std::string dat((char *)&icmp6_hdr, (char *)&icmp6_hdr +
501
    // sizeof(icmp6_hdr));
502
0
    struct necp_tlv_header header = {
503
0
        .type = (uint8_t)tlv.necp_type(),
504
0
        .length = (uint32_t)tlv.data().size(),
505
0
    };
506
0
    std::string tlv_s((char *)&header, (char *)&header + sizeof(header));
507
0
    tlv_s += tlv.data();
508
0
    parameters += tlv_s;
509
0
  }
510
0
  int retval = 0;
511
0
  necp_client_action_wrapper(fd, NECP_CLIENT_ACTION_AGENT,
512
0
                             (unsigned char *)client_id_s.data(),
513
0
                             client_id_s.size(), (uint8_t *)parameters.data(),
514
0
                             parameters.size(), &retval);
515
0
}
516
517
0
void DoNecpClientAction(const NecpClientAction &necp_client_action) {
518
0
  switch (necp_client_action.action_case()) {
519
0
    case NecpClientAction::kAdd: {
520
0
      necp_client_add(necp_client_action.necp_fd(),
521
0
                      necp_client_action.client_id(),
522
0
                      (unsigned char *)necp_client_action.add().buffer().data(),
523
0
                      necp_client_action.add().buffer().size());
524
0
      break;
525
0
    }
526
0
    case NecpClientAction::kRemove: {
527
0
      necp_client_remove(necp_client_action.necp_fd(),
528
0
                         necp_client_action.client_id());
529
0
      break;
530
0
    }
531
0
    case NecpClientAction::kCopyParameters: {
532
0
      necp_client_copy_parameters(
533
0
          necp_client_action.necp_fd(), necp_client_action.client_id(),
534
0
          necp_client_action.copy_parameters().copyout_size());
535
0
      break;
536
0
    }
537
0
    case NecpClientAction::kAgent: {
538
0
      necp_client_agent(necp_client_action.necp_fd(),
539
0
                        necp_client_action.client_id(),
540
0
                        necp_client_action.agent().necp_tlv());
541
0
      break;
542
0
    }
543
0
    case NecpClientAction::ACTION_NOT_SET: {
544
0
      break;
545
0
    }
546
0
  }
547
0
}
548
549
22.0k
void DoTcpInput(const TcpPacket &tcp_packet) {
550
22.0k
  std::string packet_s;
551
552
22.0k
  size_t expected_size =
553
22.0k
      sizeof(struct ip) + sizeof(struct tcphdr) + tcp_packet.data().size();
554
22.0k
  packet_s += get_ip_hdr(tcp_packet.ip_hdr(), expected_size);
555
22.0k
  packet_s += get_tcp_hdr(tcp_packet.tcp_hdr());
556
22.0k
  packet_s += tcp_packet.data();
557
22.0k
  assert(expected_size == packet_s.size());
558
559
22.0k
  if (packet_s.empty()) {
560
0
    return;
561
0
  }
562
563
  // TODO(nedwill): fuzz structure of mbuf itself
564
22.0k
  void *mbuf_data = get_mbuf_data(packet_s.data(), packet_s.size(), PKTF_LOOP);
565
22.0k
  if (!mbuf_data) {
566
0
    return;
567
0
  }
568
569
22.0k
  ip_input_wrapper(mbuf_data);
570
22.0k
}
571
572
30.5k
void DoTcp6Input(const Tcp6Packet &tcp6_packet) {
573
30.5k
  std::string packet_s;
574
575
  // TODO(nedwill): support hop-by-hop and other options
576
30.5k
  size_t expected_size = sizeof(struct tcphdr) + tcp6_packet.data().size();
577
30.5k
  packet_s += get_ip6_hdr(tcp6_packet.ip6_hdr(), expected_size);
578
30.5k
  packet_s += get_tcp_hdr(tcp6_packet.tcp_hdr());
579
30.5k
  packet_s += tcp6_packet.data();
580
581
30.5k
  if (packet_s.empty()) {
582
0
    return;
583
0
  }
584
585
30.5k
  void *mbuf_data = get_mbuf_data(packet_s.data(), packet_s.size(), PKTF_LOOP);
586
30.5k
  if (!mbuf_data) {
587
0
    return;
588
0
  }
589
590
30.5k
  ip6_input_wrapper(mbuf_data);
591
30.5k
}
592
593
129k
void DoIp4Packet(const Ip4Packet &packet) {
594
129k
  size_t expected_size = sizeof(struct ip) + packet.data().size();
595
129k
  std::string packet_s = get_ip_hdr(packet.ip_hdr(), expected_size);
596
129k
  packet_s += packet.data();
597
598
129k
  void *mbuf_data = get_mbuf_data(packet_s.data(), packet_s.size(), PKTF_LOOP);
599
129k
  if (!mbuf_data) {
600
0
    return;
601
0
  }
602
603
129k
  ip_input_wrapper(mbuf_data);
604
129k
}
605
606
190k
void DoIp6Packet(const Ip6Packet &packet) {
607
190k
  size_t expected_size = packet.data().size();
608
190k
  std::string packet_s = get_ip6_hdr(packet.ip6_hdr(), expected_size);
609
190k
  packet_s += packet.data();
610
611
190k
  void *mbuf_data = get_mbuf_data(packet_s.data(), packet_s.size(), PKTF_LOOP);
612
190k
  if (!mbuf_data) {
613
0
    return;
614
0
  }
615
616
190k
  ip6_input_wrapper(mbuf_data);
617
190k
}
618
619
1.01M
void DoIpInput(const Packet &packet) {
620
1.01M
  switch (packet.packet_case()) {
621
22.0k
    case Packet::kTcpPacket: {
622
22.0k
      DoTcpInput(packet.tcp_packet());
623
22.0k
      break;
624
0
    }
625
30.5k
    case Packet::kTcp6Packet: {
626
30.5k
      DoTcp6Input(packet.tcp6_packet());
627
30.5k
      break;
628
0
    }
629
129k
    case Packet::kIp4Packet: {
630
129k
      DoIp4Packet(packet.ip4_packet());
631
129k
      break;
632
0
    }
633
190k
    case Packet::kIp6Packet: {
634
190k
      DoIp6Packet(packet.ip6_packet());
635
190k
      break;
636
0
    }
637
136k
    case Packet::kRawIp4: {
638
136k
      void *mbuf_data = get_mbuf_data(packet.raw_ip4().data(),
639
136k
                                      packet.raw_ip4().size(), PKTF_LOOP);
640
136k
      if (!mbuf_data) {
641
0
        return;
642
0
      }
643
644
136k
      ip_input_wrapper(mbuf_data);
645
136k
      break;
646
136k
    }
647
81.6k
    case Packet::kRawIp6: {
648
81.6k
      void *mbuf_data = get_mbuf_data(packet.raw_ip6().data(),
649
81.6k
                                      packet.raw_ip6().size(), PKTF_LOOP);
650
81.6k
      if (!mbuf_data) {
651
0
        return;
652
0
      }
653
654
81.6k
      ip6_input_wrapper(mbuf_data);
655
81.6k
      break;
656
81.6k
    }
657
424k
    case Packet::PACKET_NOT_SET: {
658
424k
      break;
659
81.6k
    }
660
1.01M
  }
661
1.01M
}
662
663
// TODO(nedwill): make alternative build of this function that runs the
664
// the testcases against the real XNU syscalls, also KCOV-enabled
665
7.00k
DEFINE_BINARY_PROTO_FUZZER(const Session &session) {
666
  // std::string str;
667
  // google::protobuf::TextFormat::PrintToString(session, &str);
668
  // std::cout << str;
669
7.00k
  if (!ready) {
670
1
    initialize_network();
671
1
    init_proc();
672
1
    ready = true;
673
1
  }
674
675
7.00k
  FuzzedDataProvider dp((const uint8_t *)session.data_provider().data(),
676
7.00k
                        session.data_provider().size());
677
7.00k
  fdp = &dp;
678
679
  // TODO(nedwill): Make these containers own the references to their
680
  // objects so that we can use RAII to avoid leaks.
681
7.00k
  std::vector<uint32_t> cids;
682
7.00k
  std::set<int> open_fds;
683
684
11.4M
  for (const Command &command : session.commands()) {
685
11.4M
    int retval = 0;
686
11.4M
    switch (command.command_case()) {
687
57.4k
      case Command::kSocket: {
688
57.4k
        int fd = 0;
689
57.4k
        int err = socket_wrapper(command.socket().domain(),
690
57.4k
                                 command.socket().so_type(),
691
57.4k
                                 command.socket().protocol(), &fd);
692
57.4k
        if (err == 0) {
693
          // Make sure we're tracking fds properly.
694
0
          if (open_fds.find(fd) != open_fds.end()) {
695
0
            printf("Found existing fd %d\n", fd);
696
0
            assert(false);
697
0
          }
698
0
          open_fds.insert(fd);
699
0
        }
700
57.4k
        break;
701
57.4k
      }
702
111k
      case Command::kClose: {
703
111k
        open_fds.erase(command.close().fd());
704
111k
        close_wrapper(command.close().fd(), nullptr);
705
111k
        break;
706
57.4k
      }
707
122k
      case Command::kSetSockOpt: {
708
122k
        int s = command.set_sock_opt().fd();
709
122k
        int level = command.set_sock_opt().level();
710
122k
        int name = command.set_sock_opt().name();
711
122k
        size_t size = command.set_sock_opt().val().size();
712
122k
        std::unique_ptr<char[]> val(new char[size]);
713
122k
        memcpy(val.get(), command.set_sock_opt().val().data(), size);
714
122k
        setsockopt_wrapper(s, level, name, val.get(), size, nullptr);
715
122k
        break;
716
57.4k
      }
717
236k
      case Command::kGetSockOpt: {
718
236k
        int s = command.get_sock_opt().fd();
719
236k
        int level = command.get_sock_opt().level();
720
236k
        int name = command.get_sock_opt().name();
721
236k
        socklen_t size = command.get_sock_opt().size();
722
236k
        if (size < 0 || size > 4096) {
723
4.96k
          break;
724
4.96k
        }
725
231k
        std::unique_ptr<char[]> val(new char[size]);
726
231k
        getsockopt_wrapper(s, level, name, val.get(), &size, nullptr);
727
231k
        break;
728
236k
      }
729
65.7k
      case Command::kBind: {
730
65.7k
        std::string sockaddr_s = get_sockaddr(command.bind().sockaddr());
731
65.7k
        bind_wrapper(command.bind().fd(), (caddr_t)sockaddr_s.data(),
732
65.7k
                     sockaddr_s.size(), nullptr);
733
65.7k
        break;
734
236k
      }
735
413k
      case Command::kIoctl: {
736
        // TODO: pick these values more efficiently
737
        // XXX: these mutate global state
738
413k
        uint32_t fd = command.ioctl().fd();
739
413k
        uint32_t com = ioctls[command.ioctl().ioctl_idx() - 1];
740
413k
        real_copyout = false;
741
413k
        ioctl_wrapper(fd, com, /*data=*/(caddr_t)1, nullptr);
742
413k
        real_copyout = true;
743
413k
        break;
744
236k
      }
745
110k
      case Command::kAccept: {
746
110k
        std::string sockaddr_s = get_sockaddr(command.accept().sockaddr());
747
110k
        socklen_t size = sockaddr_s.size();
748
110k
        int retval = 0;
749
110k
        accept_wrapper(command.accept().fd(), (caddr_t)sockaddr_s.data(), &size,
750
110k
                       &retval);
751
110k
        break;
752
236k
      }
753
1.01M
      case Command::kIpInput: {
754
1.01M
        DoIpInput(command.ip_input());
755
1.01M
        break;
756
236k
      }
757
134k
      case Command::kIoctlReal: {
758
134k
        switch (command.ioctl_real().ioctl_case()) {
759
14.3k
          case IoctlReal::kSiocaifaddrIn664: {
760
14.3k
            const In6_AliasReq_64 &req =
761
14.3k
                command.ioctl_real().siocaifaddr_in6_64();
762
14.3k
            struct in6_aliasreq_64 alias = {};
763
14.3k
            memcpy(alias.ifra_name, req.ifra_name().data(),
764
14.3k
                   std::min(req.ifra_name().size(), sizeof(alias.ifra_name)));
765
14.3k
            get_sockaddr6(&alias.ifra_addr, req.ifra_addr());
766
14.3k
            get_sockaddr6(&alias.ifra_dstaddr, req.ifra_dstaddr());
767
14.3k
            get_sockaddr6(&alias.ifra_prefixmask, req.ifra_prefixmask());
768
14.3k
            for (int flag : req.ifra_flags()) {
769
              // make mutations that dupe a flag more useful by xoring
770
4.13k
              alias.ifra_flags ^= flag;
771
4.13k
            }
772
14.3k
            get_in6_addrlifetime_64(&alias.ifra_lifetime, req.ifra_lifetime());
773
14.3k
            ioctl_wrapper(command.ioctl_real().fd(), siocaifaddr_in6_64,
774
14.3k
                          (caddr_t)&alias, nullptr);
775
14.3k
          }
776
59.7k
          case IoctlReal::kSiocsifflags: {
777
59.7k
            struct ifreq ifreq = {};
778
59.7k
            for (int flag : command.ioctl_real().siocsifflags().flags()) {
779
51.5k
              ifreq.ifr_flags |= flag;
780
51.5k
            }
781
59.7k
            get_ifr_name(ifreq.ifr_name, LO0);
782
59.7k
            ioctl_wrapper(command.ioctl_real().fd(), siocsifflags,
783
59.7k
                          (caddr_t)&ifreq, nullptr);
784
59.7k
            break;
785
14.3k
          }
786
74.9k
          case IoctlReal::IOCTL_NOT_SET: {
787
74.9k
            break;
788
14.3k
          }
789
134k
        }
790
134k
      }
791
225k
      case Command::kConnectx: {
792
225k
        bool has_srcaddr = command.connectx().endpoints().has_sae_srcaddr();
793
794
225k
        std::string srcaddr_s;
795
225k
        if (has_srcaddr) {
796
22.3k
          srcaddr_s =
797
22.3k
              get_sockaddr(command.connectx().endpoints().sae_srcaddr());
798
22.3k
        }
799
800
225k
        std::string dstaddr_s =
801
225k
            get_sockaddr(command.connectx().endpoints().sae_dstaddr());
802
803
225k
        void *srcaddr = (void *)srcaddr_s.data();
804
225k
        uint32_t srcsize = srcaddr_s.size();
805
225k
        if (!has_srcaddr) {
806
202k
          srcaddr = nullptr;
807
202k
          assert(!srcsize);
808
202k
        }
809
810
225k
        void *dstaddr = (void *)dstaddr_s.data();
811
225k
        uint32_t dstsize = dstaddr_s.size();
812
813
        // We ignore failure here since it's ok to try to send things regardless
814
225k
        uint32_t connectx_flags = 0;
815
225k
        for (const int flag : command.connectx().flags()) {
816
13.6k
          connectx_flags |= flag;
817
13.6k
        }
818
225k
        uint32_t cid = 0;
819
820
225k
        struct user64_sa_endpoints endpoints = {
821
225k
            .sae_srcif = static_cast<unsigned int>(command.connectx().endpoints().sae_srcif()),
822
225k
            .sae_srcaddr = (user64_addr_t)srcaddr,
823
225k
            .sae_srcaddrlen = srcsize,
824
225k
            .sae_dstaddr = (user64_addr_t)dstaddr,
825
225k
            .sae_dstaddrlen = dstsize};
826
827
        // TODO(nedwill): is this a return value?
828
225k
        size_t len = 0;
829
        // TODO(nedwill): add IOV mocking
830
225k
        connectx_wrapper(command.connectx().socket(), &endpoints,
831
225k
                         command.connectx().associd(), connectx_flags, nullptr,
832
225k
                         0, &len, &cid, nullptr);
833
225k
        cids.push_back(cid);
834
225k
        break;
835
225k
      }
836
71.2k
      case Command::kConnect: {
837
71.2k
        std::string sockaddr_s = get_sockaddr(command.connect().sockaddr());
838
71.2k
        connect_wrapper(command.connect().fd(), (caddr_t)sockaddr_s.data(),
839
71.2k
                        sockaddr_s.size(), nullptr);
840
71.2k
        break;
841
225k
      }
842
76.5k
      case Command::kListen: {
843
76.5k
        listen_wrapper(command.listen().socket(), command.listen().backlog(),
844
76.5k
                       nullptr);
845
76.5k
        break;
846
225k
      }
847
53.1k
      case Command::kDisconnectx: {
848
53.1k
        uint32_t cid = 0;
849
53.1k
        if (!cids.empty()) {
850
51.1k
          cid = cids[command.disconnectx().cid() % cids.size()];
851
51.1k
        } else {
852
1.95k
          cid = command.disconnectx().cid();
853
1.95k
        }
854
53.1k
        disconnectx_wrapper(command.disconnectx().fd(),
855
53.1k
                            command.disconnectx().associd(), cid, nullptr);
856
53.1k
        break;
857
225k
      }
858
256k
      case Command::kClearAll: {
859
        // TODO(nedwill): finer-grained calling of clear_all functions here
860
256k
        clear_all();
861
256k
        break;
862
225k
      }
863
45.0k
      case Command::kNecpMatchPolicy: {
864
45.0k
        std::unique_ptr<uint8_t[]> parameters_u8(
865
45.0k
            new uint8_t[command.necp_match_policy().parameters().size()]);
866
45.0k
        memcpy(parameters_u8.get(),
867
45.0k
               command.necp_match_policy().parameters().data(),
868
45.0k
               command.necp_match_policy().parameters().size());
869
        // necp_match_policy_wrapper(
870
        //     parameters_u8.get(),
871
        //     command.necp_match_policy().parameters().size(),
872
        //     /*returned_result*/ nullptr, nullptr);
873
45.0k
        break;
874
225k
      }
875
107k
      case Command::kNecpOpen: {
876
        // int flags = 0;
877
        // for (int flag : command.necp_open().flags()) {
878
        //   flags |= flag;
879
        // }
880
        // int fd = 0;
881
        // int err = necp_open_wrapper(flags, &fd);
882
        // if (err == 0) {
883
        //   if (open_fds.find(fd) != open_fds.end()) {
884
        //     printf("fd %d already in open sockets\n", fd);
885
        //     assert(false);
886
        //   }
887
        //   open_fds.insert(fd);
888
        // }
889
107k
        break;
890
225k
      }
891
71.6k
      case Command::kNecpClientAction: {
892
        // DoNecpClientAction(command.necp_client_action());
893
71.6k
        break;
894
225k
      }
895
94.5k
      case Command::kNecpSessionOpen: {
896
        // int flags = 0;
897
        // int fd = 0;
898
        // int err = necp_session_open_wrapper(flags, &fd);
899
        // if (err == 0) {
900
        //   if (open_fds.find(fd) != open_fds.end()) {
901
        //     printf("fd %d already in open sockets\n", fd);
902
        //     assert(false);
903
        //   }
904
        //   open_fds.insert(fd);
905
        // }
906
94.5k
        break;
907
225k
      }
908
89.0k
      case Command::kNecpSessionAction: {
909
89.0k
        size_t out_buffer_size =
910
89.0k
            command.necp_session_action().out_buffer_size() % 4096;
911
89.0k
        std::unique_ptr<uint8_t[]> out_buffer(new uint8_t[out_buffer_size]);
912
        // necp_session_action_wrapper(
913
        //     command.necp_session_action().necp_fd(),
914
        //     command.necp_session_action().action(),
915
        //     // TODO(nedwill): fix const cast
916
        //     (uint8_t *)command.necp_session_action().in_buffer().data(),
917
        //     command.necp_session_action().in_buffer().size(), out_buffer.get(),
918
        //     out_buffer_size, &retval);
919
89.0k
        break;
920
225k
      }
921
74.2k
      case Command::kAcceptNocancel: {
922
74.2k
        std::string sockaddr_s = get_sockaddr(command.accept_nocancel().name());
923
74.2k
        socklen_t size = sockaddr_s.size();
924
74.2k
        accept_nocancel_wrapper(command.accept_nocancel().s(),
925
74.2k
                                (caddr_t)sockaddr_s.data(), &size, &retval);
926
74.2k
        break;
927
225k
      }
928
92.3k
      case Command::kConnectNocancel: {
929
92.3k
        std::string sockaddr_s =
930
92.3k
            get_sockaddr(command.connect_nocancel().name());
931
92.3k
        socklen_t size = sockaddr_s.size();
932
92.3k
        connect_nocancel_wrapper(command.connect_nocancel().s(),
933
92.3k
                                 (caddr_t)sockaddr_s.data(), size, &retval);
934
92.3k
        break;
935
225k
      }
936
77.6k
      case Command::kGetpeername: {
937
77.6k
        std::string sockaddr_s = get_sockaddr(command.getpeername().asa());
938
77.6k
        socklen_t size = sockaddr_s.size();
939
77.6k
        getpeername_wrapper(command.getpeername().fdes(),
940
77.6k
                            (caddr_t)sockaddr_s.data(), &size, &retval);
941
77.6k
        break;
942
225k
      }
943
62.3k
      case Command::kGetsockname: {
944
62.3k
        std::string sockaddr_s = get_sockaddr(command.getsockname().asa());
945
62.3k
        socklen_t size = sockaddr_s.size();
946
62.3k
        getsockname_wrapper(command.getsockname().fdes(),
947
62.3k
                            (caddr_t)sockaddr_s.data(), &size, &retval);
948
62.3k
        break;
949
225k
      }
950
72.6k
      case Command::kPeeloff: {
951
72.6k
        peeloff_wrapper(command.peeloff().s(), command.peeloff().aid(),
952
72.6k
                        &retval);
953
72.6k
        break;
954
225k
      }
955
54.5k
      case Command::kRecvfrom: {
956
54.5k
        std::string sockaddr_s = get_sockaddr(command.recvfrom().from());
957
54.5k
        int size = sockaddr_s.size();
958
        // TODO(nedwill): just specify the size of the buffer, don't store bytes
959
        // in the proto message just for them to be overwritten
960
54.5k
        recvfrom_wrapper(
961
54.5k
            command.recvfrom().s(), (caddr_t)command.recvfrom().buf().data(),
962
54.5k
            command.recvfrom().buf().size(), command.recvfrom().flags(),
963
54.5k
            (struct sockaddr *)sockaddr_s.data(), &size, &retval);
964
54.5k
        break;
965
225k
      }
966
54.8k
      case Command::kRecvfromNocancel: {
967
54.8k
        std::string sockaddr_s =
968
54.8k
            get_sockaddr(command.recvfrom_nocancel().from());
969
54.8k
        int size = sockaddr_s.size();
970
54.8k
        recvfrom_nocancel_wrapper(
971
54.8k
            command.recvfrom_nocancel().s(),
972
54.8k
            (caddr_t)command.recvfrom_nocancel().buf().data(),
973
54.8k
            command.recvfrom_nocancel().buf().size(),
974
54.8k
            command.recvfrom_nocancel().flags(),
975
54.8k
            (struct sockaddr *)sockaddr_s.data(), &size, &retval);
976
54.8k
        break;
977
225k
      }
978
69.3k
      case Command::kRecvmsg: {
979
        // TODO(nedwill): fuzz this msg field
980
69.3k
        user64_msghdr msg = {};
981
69.3k
        recvmsg_wrapper(command.recvmsg().s(), (struct msghdr *)&msg,
982
69.3k
                        command.recvmsg().flags(), &retval);
983
69.3k
        break;
984
225k
      }
985
118k
      case Command::kSendto: {
986
118k
        std::string sockaddr_s = get_sockaddr(command.sendto().to());
987
118k
        socklen_t size = sockaddr_s.size();
988
118k
        sendto_wrapper(command.sendto().s(),
989
118k
                       (caddr_t)command.sendto().buf().data(),
990
118k
                       command.sendto().buf().size(), command.sendto().flags(),
991
118k
                       (caddr_t)sockaddr_s.data(), size, &retval);
992
118k
        break;
993
225k
      }
994
1.25M
      case Command::kSocketpair: {
995
1.25M
        int rsv[2] = {};
996
1.25M
        int ret = socketpair_wrapper(
997
1.25M
            command.socketpair().domain(), command.socketpair().type(),
998
1.25M
            command.socketpair().protocol(), rsv, &retval);
999
1.25M
        if (!ret) {
1000
3
          if (open_fds.find(rsv[0]) != open_fds.end()) {
1001
0
            assert(false);
1002
0
          }
1003
3
          open_fds.insert(rsv[0]);
1004
3
          if (open_fds.find(rsv[1]) != open_fds.end()) {
1005
0
            assert(false);
1006
0
          }
1007
3
          open_fds.insert(rsv[1]);
1008
3
        }
1009
1.25M
        break;
1010
1.25M
      }
1011
1.25M
      case Command::kPipe: {
1012
131k
        int rsv[2] = {};
1013
131k
        int ret = pipe_wrapper(rsv);
1014
131k
        if (!ret) {
1015
2
          if (open_fds.find(rsv[0]) != open_fds.end()) {
1016
0
            assert(false);
1017
0
          }
1018
2
          open_fds.insert(rsv[0]);
1019
2
          if (open_fds.find(rsv[1]) != open_fds.end()) {
1020
0
            assert(false);
1021
0
          }
1022
2
          open_fds.insert(rsv[1]);
1023
2
        }
1024
131k
        break;
1025
131k
      }
1026
131k
      case Command::kShutdown: {
1027
88.4k
        shutdown_wrapper(command.shutdown().s(), command.shutdown().how(),
1028
88.4k
                         &retval);
1029
88.4k
        break;
1030
131k
      }
1031
6.11M
      case Command::COMMAND_NOT_SET: {
1032
6.11M
        break;
1033
131k
      }
1034
11.4M
    }
1035
11.4M
  }
1036
1037
7.00k
  for (int fd : open_fds) {
1038
10
    int err = close_wrapper(fd, nullptr);
1039
10
    assert(err != EBADF);
1040
10
  }
1041
1042
  // TODO(nedwill): split up these worker threads and run them as
1043
  // part of main loop
1044
7.00k
  clear_all();
1045
7.00k
}
1046
}