/src/quiche/fuzz/src/lib.rs
Line | Count | Source |
1 | | use std::path::Path; |
2 | | use std::path::PathBuf; |
3 | | |
4 | | use quiche::h3::NameValue; |
5 | | |
6 | | pub struct PktsData<'a> { |
7 | | pub data: &'a [u8], |
8 | | } |
9 | | |
10 | | pub struct PktIterator<'a> { |
11 | | data: &'a [u8], |
12 | | index: usize, |
13 | | } |
14 | | |
15 | | impl<'a> Iterator for PktIterator<'a> { |
16 | | type Item = &'a [u8]; |
17 | | |
18 | 8.88M | fn next(&mut self) -> Option<Self::Item> { |
19 | 8.88M | if self.index < self.data.len() { |
20 | 8.86M | let start = self.index; |
21 | 8.86M | if self.index + 4 <= self.data.len() { |
22 | 365M | for i in self.index..self.data.len() - 4 { |
23 | 365M | if &self.data[i..i + 4] == b"fuzz" { |
24 | 8.84M | self.index = i + 4; |
25 | 8.84M | return Some(&self.data[start..i]); |
26 | 356M | } |
27 | | } |
28 | 985 | } |
29 | 19.7k | self.index = self.data.len(); |
30 | 19.7k | Some(&self.data[start..]) |
31 | | } else { |
32 | 19.7k | None |
33 | | } |
34 | 8.88M | } |
35 | | } |
36 | | |
37 | | impl<'a> PktsData<'a> { |
38 | 19.7k | pub fn iter(&self) -> PktIterator<'_> { |
39 | 19.7k | PktIterator { |
40 | 19.7k | data: self.data, |
41 | 19.7k | index: 0, |
42 | 19.7k | } |
43 | 19.7k | } |
44 | | } |
45 | | |
46 | 31.5k | pub fn reset_rand_for_fuzzing() { |
47 | | extern "C" { |
48 | | fn RAND_reset_for_fuzzing(); |
49 | | } |
50 | | |
51 | 31.5k | unsafe { RAND_reset_for_fuzzing() }; |
52 | 31.5k | } |
53 | | |
54 | | /// Returns the path to the X.509 certificate and key. |
55 | | /// |
56 | | /// If `QUICHE_FUZZ_CRT` and / or `QUICHE_FUZZ_KEY` are set, their value is |
57 | | /// used, otherwise in order to accomodate different fuzzing environments, this |
58 | | /// either returns relative paths (e.g. "fuzz/cert.crt") when running from a |
59 | | /// clone of the git repository, or absolute paths based on `argv[0]` when |
60 | | /// running bare executable (as used by OSS-Fuzz). |
61 | 3 | pub fn get_cert_path() -> (String, String) { |
62 | 3 | let fuzz_dir = if Path::new("fuzz/").exists() { |
63 | 3 | PathBuf::from("fuzz/") |
64 | | } else { |
65 | | // Get directory the fuzzer is running from. |
66 | 0 | let mut fuzz_dir = PathBuf::from(std::env::args().next().unwrap()); |
67 | | // Remove executable file name. |
68 | 0 | fuzz_dir.pop(); |
69 | | // Add "fuzz" subdirectory. |
70 | 0 | fuzz_dir.push("fuzz"); |
71 | | |
72 | 0 | fuzz_dir |
73 | | }; |
74 | | |
75 | 3 | let crt_path = std::env::var("QUICHE_FUZZ_CRT").unwrap_or_else(|_| { |
76 | 3 | let mut crt_path = fuzz_dir.clone(); |
77 | 3 | crt_path.push("cert.crt"); |
78 | 3 | crt_path.to_str().unwrap().to_string() |
79 | 3 | }); |
80 | | |
81 | 3 | let key_path = std::env::var("QUICHE_FUZZ_KEY").unwrap_or_else(|_| { |
82 | 3 | let mut key_path = fuzz_dir.clone(); |
83 | 3 | key_path.push("cert.key"); |
84 | 3 | key_path.to_str().unwrap().to_string() |
85 | 3 | }); |
86 | | |
87 | 3 | (crt_path, key_path) |
88 | 3 | } |
89 | | |
90 | 8.86M | pub fn server_process( |
91 | 8.86M | pkt: &[u8], conn: &mut quiche::Connection, |
92 | 8.86M | h3_conn: &mut Option<quiche::h3::Connection>, info: quiche::RecvInfo, |
93 | 8.86M | ) { |
94 | 8.86M | let mut buf = pkt.to_vec(); |
95 | 8.86M | conn.recv(&mut buf, info).ok(); |
96 | | |
97 | 8.86M | if (conn.is_in_early_data() || conn.is_established()) && h3_conn.is_none() { |
98 | 17.8k | let h3_config = quiche::h3::Config::new().unwrap(); |
99 | | |
100 | 17.8k | if let Ok(c) = quiche::h3::Connection::with_transport(conn, &h3_config) { |
101 | 13.5k | *h3_conn = Some(c); |
102 | 13.5k | } |
103 | 8.84M | } |
104 | | |
105 | 8.86M | if h3_conn.is_some() { |
106 | 4.64M | let h3c = h3_conn.as_mut().unwrap(); |
107 | | loop { |
108 | 4.64M | let r = h3c.poll(conn); |
109 | | |
110 | 6.48k | match r { |
111 | | Ok(( |
112 | 260 | _stream_id, |
113 | | quiche::h3::Event::Headers { |
114 | 260 | list, |
115 | | more_frames: _, |
116 | | }, |
117 | | )) => { |
118 | 260 | let mut headers = list.into_iter(); |
119 | | |
120 | | // Look for the request's method. |
121 | 291 | let method = headers.find(|h| h.name() == b":method"); |
122 | 260 | if method.is_none() { |
123 | 241 | break; |
124 | 19 | } |
125 | 19 | let method = method.unwrap(); |
126 | | |
127 | | // Look for the request's path. |
128 | 37 | let path = headers.find(|h| h.name() == b":path"); |
129 | 19 | if path.is_none() { |
130 | 14 | break; |
131 | 5 | } |
132 | 5 | let path = path.unwrap(); |
133 | | |
134 | 5 | if method.value() == b"GET" && path.value() == b"/" { |
135 | 3 | let _resp = vec![ |
136 | 3 | quiche::h3::Header::new( |
137 | 3 | b":status", |
138 | 3 | 200.to_string().as_bytes(), |
139 | 3 | ), |
140 | 3 | quiche::h3::Header::new(b"server", b"quiche"), |
141 | 3 | ]; |
142 | 3 | } |
143 | | }, |
144 | | |
145 | 203 | Ok((_stream_id, quiche::h3::Event::Data)) => {}, |
146 | | |
147 | 1.68k | Ok((_stream_id, quiche::h3::Event::Finished)) => {}, |
148 | | |
149 | 4.32k | Ok((_stream_id, quiche::h3::Event::Reset(_err))) => {}, |
150 | | |
151 | 0 | Ok((_flow_id, quiche::h3::Event::PriorityUpdate)) => {}, |
152 | | |
153 | 16 | Ok((_goaway_id, quiche::h3::Event::GoAway)) => { |
154 | 16 | // Peer signalled it is going away, handle it. |
155 | 16 | }, |
156 | | |
157 | | Err(quiche::h3::Error::Done) => { |
158 | | // Done reading. |
159 | 4.64M | break; |
160 | | }, |
161 | | |
162 | 711 | Err(_e) => { |
163 | | // An error occurred, handle it. |
164 | 711 | break; |
165 | | }, |
166 | | } |
167 | | } |
168 | 4.22M | } |
169 | | |
170 | 8.86M | let mut out_buf = [0; 1500]; |
171 | 10.2M | while conn.send(&mut out_buf).is_ok() {} |
172 | 8.86M | } |