1 // Copyright (C) 2018-2019, Cloudflare, Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright notice,
9 //       this list of conditions and the following disclaimer.
10 //
11 //     * Redistributions in binary form must reproduce the above copyright
12 //       notice, this list of conditions and the following disclaimer in the
13 //       documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 #[macro_use]
28 extern crate log;
29 
30 use std::net;
31 
32 use std::collections::HashMap;
33 
34 use ring::rand::*;
35 
36 const MAX_DATAGRAM_SIZE: usize = 1350;
37 
38 struct PartialResponse {
39     body: Vec<u8>,
40 
41     written: usize,
42 }
43 
44 struct Client {
45     conn: quiche::Connection,
46 
47     partial_responses: HashMap<u64, PartialResponse>,
48 }
49 
50 type ClientMap = HashMap<quiche::ConnectionId<'static>, Client>;
51 
main()52 fn main() {
53     let mut buf = [0; 65535];
54     let mut out = [0; MAX_DATAGRAM_SIZE];
55 
56     let mut args = std::env::args();
57 
58     let cmd = &args.next().unwrap();
59 
60     if args.len() != 0 {
61         println!("Usage: {cmd}");
62         println!("\nSee tools/apps/ for more complete implementations.");
63         return;
64     }
65 
66     // Setup the event loop.
67     let mut poll = mio::Poll::new().unwrap();
68     let mut events = mio::Events::with_capacity(1024);
69 
70     // Create the UDP listening socket, and register it with the event loop.
71     let mut socket =
72         mio::net::UdpSocket::bind("127.0.0.1:4433".parse().unwrap()).unwrap();
73     poll.registry()
74         .register(&mut socket, mio::Token(0), mio::Interest::READABLE)
75         .unwrap();
76 
77     // Create the configuration for the QUIC connections.
78     let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
79 
80     config
81         .load_cert_chain_from_pem_file("examples/cert.crt")
82         .unwrap();
83     config
84         .load_priv_key_from_pem_file("examples/cert.key")
85         .unwrap();
86 
87     config
88         .set_application_protos(&[
89             b"hq-interop",
90             b"hq-29",
91             b"hq-28",
92             b"hq-27",
93             b"http/0.9",
94         ])
95         .unwrap();
96 
97     config.set_max_idle_timeout(5000);
98     config.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE);
99     config.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE);
100     config.set_initial_max_data(10_000_000);
101     config.set_initial_max_stream_data_bidi_local(1_000_000);
102     config.set_initial_max_stream_data_bidi_remote(1_000_000);
103     config.set_initial_max_stream_data_uni(1_000_000);
104     config.set_initial_max_streams_bidi(100);
105     config.set_initial_max_streams_uni(100);
106     config.set_disable_active_migration(true);
107     config.enable_early_data();
108 
109     let rng = SystemRandom::new();
110     let conn_id_seed =
111         ring::hmac::Key::generate(ring::hmac::HMAC_SHA256, &rng).unwrap();
112 
113     let mut clients = ClientMap::new();
114 
115     let local_addr = socket.local_addr().unwrap();
116 
117     loop {
118         // Find the shorter timeout from all the active connections.
119         //
120         // TODO: use event loop that properly supports timers
121         let timeout = clients.values().filter_map(|c| c.conn.timeout()).min();
122 
123         poll.poll(&mut events, timeout).unwrap();
124 
125         // Read incoming UDP packets from the socket and feed them to quiche,
126         // until there are no more packets to read.
127         'read: loop {
128             // If the event loop reported no events, it means that the timeout
129             // has expired, so handle it without attempting to read packets. We
130             // will then proceed with the send loop.
131             if events.is_empty() {
132                 debug!("timed out");
133 
134                 clients.values_mut().for_each(|c| c.conn.on_timeout());
135 
136                 break 'read;
137             }
138 
139             let (len, from) = match socket.recv_from(&mut buf) {
140                 Ok(v) => v,
141 
142                 Err(e) => {
143                     // There are no more UDP packets to read, so end the read
144                     // loop.
145                     if e.kind() == std::io::ErrorKind::WouldBlock {
146                         debug!("recv() would block");
147                         break 'read;
148                     }
149 
150                     panic!("recv() failed: {:?}", e);
151                 },
152             };
153 
154             debug!("got {} bytes", len);
155 
156             let pkt_buf = &mut buf[..len];
157 
158             // Parse the QUIC packet's header.
159             let hdr = match quiche::Header::from_slice(
160                 pkt_buf,
161                 quiche::MAX_CONN_ID_LEN,
162             ) {
163                 Ok(v) => v,
164 
165                 Err(e) => {
166                     error!("Parsing packet header failed: {:?}", e);
167                     continue 'read;
168                 },
169             };
170 
171             trace!("got packet {:?}", hdr);
172 
173             let conn_id = ring::hmac::sign(&conn_id_seed, &hdr.dcid);
174             let conn_id = &conn_id.as_ref()[..quiche::MAX_CONN_ID_LEN];
175             let conn_id = conn_id.to_vec().into();
176 
177             // Lookup a connection based on the packet's connection ID. If there
178             // is no connection matching, create a new one.
179             let client = if !clients.contains_key(&hdr.dcid) &&
180                 !clients.contains_key(&conn_id)
181             {
182                 if hdr.ty != quiche::Type::Initial {
183                     error!("Packet is not Initial");
184                     continue 'read;
185                 }
186 
187                 if !quiche::version_is_supported(hdr.version) {
188                     warn!("Doing version negotiation");
189 
190                     let len =
191                         quiche::negotiate_version(&hdr.scid, &hdr.dcid, &mut out)
192                             .unwrap();
193 
194                     let out = &out[..len];
195 
196                     if let Err(e) = socket.send_to(out, from) {
197                         if e.kind() == std::io::ErrorKind::WouldBlock {
198                             debug!("send() would block");
199                             break;
200                         }
201 
202                         panic!("send() failed: {:?}", e);
203                     }
204                     continue 'read;
205                 }
206 
207                 let mut scid = [0; quiche::MAX_CONN_ID_LEN];
208                 scid.copy_from_slice(&conn_id);
209 
210                 let scid = quiche::ConnectionId::from_ref(&scid);
211 
212                 // Token is always present in Initial packets.
213                 let token = hdr.token.as_ref().unwrap();
214 
215                 // Do stateless retry if the client didn't send a token.
216                 if token.is_empty() {
217                     warn!("Doing stateless retry");
218 
219                     let new_token = mint_token(&hdr, &from);
220 
221                     let len = quiche::retry(
222                         &hdr.scid,
223                         &hdr.dcid,
224                         &scid,
225                         &new_token,
226                         hdr.version,
227                         &mut out,
228                     )
229                     .unwrap();
230 
231                     let out = &out[..len];
232 
233                     if let Err(e) = socket.send_to(out, from) {
234                         if e.kind() == std::io::ErrorKind::WouldBlock {
235                             debug!("send() would block");
236                             break;
237                         }
238 
239                         panic!("send() failed: {:?}", e);
240                     }
241                     continue 'read;
242                 }
243 
244                 let odcid = validate_token(&from, token);
245 
246                 // The token was not valid, meaning the retry failed, so
247                 // drop the packet.
248                 if odcid.is_none() {
249                     error!("Invalid address validation token");
250                     continue 'read;
251                 }
252 
253                 if scid.len() != hdr.dcid.len() {
254                     error!("Invalid destination connection ID");
255                     continue 'read;
256                 }
257 
258                 // Reuse the source connection ID we sent in the Retry packet,
259                 // instead of changing it again.
260                 let scid = hdr.dcid.clone();
261 
262                 debug!("New connection: dcid={:?} scid={:?}", hdr.dcid, scid);
263 
264                 let conn = quiche::accept(
265                     &scid,
266                     odcid.as_ref(),
267                     local_addr,
268                     from,
269                     &mut config,
270                 )
271                 .unwrap();
272 
273                 let client = Client {
274                     conn,
275                     partial_responses: HashMap::new(),
276                 };
277 
278                 clients.insert(scid.clone(), client);
279 
280                 clients.get_mut(&scid).unwrap()
281             } else {
282                 match clients.get_mut(&hdr.dcid) {
283                     Some(v) => v,
284 
285                     None => clients.get_mut(&conn_id).unwrap(),
286                 }
287             };
288 
289             let recv_info = quiche::RecvInfo {
290                 to: socket.local_addr().unwrap(),
291                 from,
292             };
293 
294             // Process potentially coalesced packets.
295             let read = match client.conn.recv(pkt_buf, recv_info) {
296                 Ok(v) => v,
297 
298                 Err(e) => {
299                     error!("{} recv failed: {:?}", client.conn.trace_id(), e);
300                     continue 'read;
301                 },
302             };
303 
304             debug!("{} processed {} bytes", client.conn.trace_id(), read);
305 
306             if client.conn.is_in_early_data() || client.conn.is_established() {
307                 // Handle writable streams.
308                 for stream_id in client.conn.writable() {
309                     handle_writable(client, stream_id);
310                 }
311 
312                 // Process all readable streams.
313                 for s in client.conn.readable() {
314                     while let Ok((read, fin)) =
315                         client.conn.stream_recv(s, &mut buf)
316                     {
317                         debug!(
318                             "{} received {} bytes",
319                             client.conn.trace_id(),
320                             read
321                         );
322 
323                         let stream_buf = &buf[..read];
324 
325                         debug!(
326                             "{} stream {} has {} bytes (fin? {})",
327                             client.conn.trace_id(),
328                             s,
329                             stream_buf.len(),
330                             fin
331                         );
332 
333                         handle_stream(client, s, stream_buf, "examples/root");
334                     }
335                 }
336             }
337         }
338 
339         // Generate outgoing QUIC packets for all active connections and send
340         // them on the UDP socket, until quiche reports that there are no more
341         // packets to be sent.
342         for client in clients.values_mut() {
343             loop {
344                 let (write, send_info) = match client.conn.send(&mut out) {
345                     Ok(v) => v,
346 
347                     Err(quiche::Error::Done) => {
348                         debug!("{} done writing", client.conn.trace_id());
349                         break;
350                     },
351 
352                     Err(e) => {
353                         error!("{} send failed: {:?}", client.conn.trace_id(), e);
354 
355                         client.conn.close(false, 0x1, b"fail").ok();
356                         break;
357                     },
358                 };
359 
360                 if let Err(e) = socket.send_to(&out[..write], send_info.to) {
361                     if e.kind() == std::io::ErrorKind::WouldBlock {
362                         debug!("send() would block");
363                         break;
364                     }
365 
366                     panic!("send() failed: {:?}", e);
367                 }
368 
369                 debug!("{} written {} bytes", client.conn.trace_id(), write);
370             }
371         }
372 
373         // Garbage collect closed connections.
374         clients.retain(|_, ref mut c| {
375             debug!("Collecting garbage");
376 
377             if c.conn.is_closed() {
378                 info!(
379                     "{} connection collected {:?}",
380                     c.conn.trace_id(),
381                     c.conn.stats()
382                 );
383             }
384 
385             !c.conn.is_closed()
386         });
387     }
388 }
389 
390 /// Generate a stateless retry token.
391 ///
392 /// The token includes the static string `"quiche"` followed by the IP address
393 /// of the client and by the original destination connection ID generated by the
394 /// client.
395 ///
396 /// Note that this function is only an example and doesn't do any cryptographic
397 /// authenticate of the token. *It should not be used in production system*.
mint_token(hdr: &quiche::Header, src: &net::SocketAddr) -> Vec<u8>398 fn mint_token(hdr: &quiche::Header, src: &net::SocketAddr) -> Vec<u8> {
399     let mut token = Vec::new();
400 
401     token.extend_from_slice(b"quiche");
402 
403     let addr = match src.ip() {
404         std::net::IpAddr::V4(a) => a.octets().to_vec(),
405         std::net::IpAddr::V6(a) => a.octets().to_vec(),
406     };
407 
408     token.extend_from_slice(&addr);
409     token.extend_from_slice(&hdr.dcid);
410 
411     token
412 }
413 
414 /// Validates a stateless retry token.
415 ///
416 /// This checks that the ticket includes the `"quiche"` static string, and that
417 /// the client IP address matches the address stored in the ticket.
418 ///
419 /// Note that this function is only an example and doesn't do any cryptographic
420 /// authenticate of the token. *It should not be used in production system*.
validate_token<'a>( src: &net::SocketAddr, token: &'a [u8], ) -> Option<quiche::ConnectionId<'a>>421 fn validate_token<'a>(
422     src: &net::SocketAddr, token: &'a [u8],
423 ) -> Option<quiche::ConnectionId<'a>> {
424     if token.len() < 6 {
425         return None;
426     }
427 
428     if &token[..6] != b"quiche" {
429         return None;
430     }
431 
432     let token = &token[6..];
433 
434     let addr = match src.ip() {
435         std::net::IpAddr::V4(a) => a.octets().to_vec(),
436         std::net::IpAddr::V6(a) => a.octets().to_vec(),
437     };
438 
439     if token.len() < addr.len() || &token[..addr.len()] != addr.as_slice() {
440         return None;
441     }
442 
443     Some(quiche::ConnectionId::from_ref(&token[addr.len()..]))
444 }
445 
446 /// Handles incoming HTTP/0.9 requests.
handle_stream(client: &mut Client, stream_id: u64, buf: &[u8], root: &str)447 fn handle_stream(client: &mut Client, stream_id: u64, buf: &[u8], root: &str) {
448     let conn = &mut client.conn;
449 
450     if buf.len() > 4 && &buf[..4] == b"GET " {
451         let uri = &buf[4..buf.len()];
452         let uri = String::from_utf8(uri.to_vec()).unwrap();
453         let uri = String::from(uri.lines().next().unwrap());
454         let uri = std::path::Path::new(&uri);
455         let mut path = std::path::PathBuf::from(root);
456 
457         for c in uri.components() {
458             if let std::path::Component::Normal(v) = c {
459                 path.push(v)
460             }
461         }
462 
463         info!(
464             "{} got GET request for {:?} on stream {}",
465             conn.trace_id(),
466             path,
467             stream_id
468         );
469 
470         let body = std::fs::read(path.as_path())
471             .unwrap_or_else(|_| b"Not Found!\r\n".to_vec());
472 
473         info!(
474             "{} sending response of size {} on stream {}",
475             conn.trace_id(),
476             body.len(),
477             stream_id
478         );
479 
480         let written = match conn.stream_send(stream_id, &body, true) {
481             Ok(v) => v,
482 
483             Err(quiche::Error::Done) => 0,
484 
485             Err(e) => {
486                 error!("{} stream send failed {:?}", conn.trace_id(), e);
487                 return;
488             },
489         };
490 
491         if written < body.len() {
492             let response = PartialResponse { body, written };
493             client.partial_responses.insert(stream_id, response);
494         }
495     }
496 }
497 
498 /// Handles newly writable streams.
handle_writable(client: &mut Client, stream_id: u64)499 fn handle_writable(client: &mut Client, stream_id: u64) {
500     let conn = &mut client.conn;
501 
502     debug!("{} stream {} is writable", conn.trace_id(), stream_id);
503 
504     if !client.partial_responses.contains_key(&stream_id) {
505         return;
506     }
507 
508     let resp = client.partial_responses.get_mut(&stream_id).unwrap();
509     let body = &resp.body[resp.written..];
510 
511     let written = match conn.stream_send(stream_id, body, true) {
512         Ok(v) => v,
513 
514         Err(quiche::Error::Done) => 0,
515 
516         Err(e) => {
517             client.partial_responses.remove(&stream_id);
518 
519             error!("{} stream send failed {:?}", conn.trace_id(), e);
520             return;
521         },
522     };
523 
524     resp.written += written;
525 
526     if resp.written == resp.body.len() {
527         client.partial_responses.remove(&stream_id);
528     }
529 }
530