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: std::pin::Pin<Box<quiche::Connection>>,
46 
47     partial_responses: HashMap<u64, PartialResponse>,
48 }
49 
50 type ClientMap = HashMap<Vec<u8>, (net::SocketAddr, 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 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 socket = net::UdpSocket::bind("127.0.0.1:4433").unwrap();
72 
73     let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
74     poll.register(
75         &socket,
76         mio::Token(0),
77         mio::Ready::readable(),
78         mio::PollOpt::edge(),
79     )
80     .unwrap();
81 
82     // Create the configuration for the QUIC connections.
83     let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
84 
85     config
86         .load_cert_chain_from_pem_file("examples/cert.crt")
87         .unwrap();
88     config
89         .load_priv_key_from_pem_file("examples/cert.key")
90         .unwrap();
91 
92     config
93         .set_application_protos(b"\x05hq-29\x05hq-28\x05hq-27\x08http/0.9")
94         .unwrap();
95 
96     config.set_max_idle_timeout(5000);
97     config.set_max_udp_payload_size(MAX_DATAGRAM_SIZE as u64);
98     config.set_initial_max_data(10_000_000);
99     config.set_initial_max_stream_data_bidi_local(1_000_000);
100     config.set_initial_max_stream_data_bidi_remote(1_000_000);
101     config.set_initial_max_stream_data_uni(1_000_000);
102     config.set_initial_max_streams_bidi(100);
103     config.set_initial_max_streams_uni(100);
104     config.set_disable_active_migration(true);
105     config.enable_early_data();
106 
107     let rng = SystemRandom::new();
108     let conn_id_seed =
109         ring::hmac::Key::generate(ring::hmac::HMAC_SHA256, &rng).unwrap();
110 
111     let mut clients = ClientMap::new();
112 
113     loop {
114         // Find the shorter timeout from all the active connections.
115         //
116         // TODO: use event loop that properly supports timers
117         let timeout =
118             clients.values().filter_map(|(_, c)| c.conn.timeout()).min();
119 
120         poll.poll(&mut events, timeout).unwrap();
121 
122         // Read incoming UDP packets from the socket and feed them to quiche,
123         // until there are no more packets to read.
124         'read: loop {
125             // If the event loop reported no events, it means that the timeout
126             // has expired, so handle it without attempting to read packets. We
127             // will then proceed with the send loop.
128             if events.is_empty() {
129                 debug!("timed out");
130 
131                 clients.values_mut().for_each(|(_, c)| c.conn.on_timeout());
132 
133                 break 'read;
134             }
135 
136             let (len, src) = match socket.recv_from(&mut buf) {
137                 Ok(v) => v,
138 
139                 Err(e) => {
140                     // There are no more UDP packets to read, so end the read
141                     // loop.
142                     if e.kind() == std::io::ErrorKind::WouldBlock {
143                         debug!("recv() would block");
144                         break 'read;
145                     }
146 
147                     panic!("recv() failed: {:?}", e);
148                 },
149             };
150 
151             debug!("got {} bytes", len);
152 
153             let pkt_buf = &mut buf[..len];
154 
155             // Parse the QUIC packet's header.
156             let hdr = match quiche::Header::from_slice(
157                 pkt_buf,
158                 quiche::MAX_CONN_ID_LEN,
159             ) {
160                 Ok(v) => v,
161 
162                 Err(e) => {
163                     error!("Parsing packet header failed: {:?}", e);
164                     continue 'read;
165                 },
166             };
167 
168             trace!("got packet {:?}", hdr);
169 
170             let conn_id = ring::hmac::sign(&conn_id_seed, &hdr.dcid);
171             let conn_id = &conn_id.as_ref()[..quiche::MAX_CONN_ID_LEN];
172 
173             // Lookup a connection based on the packet's connection ID. If there
174             // is no connection matching, create a new one.
175             let (_, client) = if !clients.contains_key(&hdr.dcid) &&
176                 !clients.contains_key(conn_id)
177             {
178                 if hdr.ty != quiche::Type::Initial {
179                     error!("Packet is not Initial");
180                     continue 'read;
181                 }
182 
183                 if !quiche::version_is_supported(hdr.version) {
184                     warn!("Doing version negotiation");
185 
186                     let len =
187                         quiche::negotiate_version(&hdr.scid, &hdr.dcid, &mut out)
188                             .unwrap();
189 
190                     let out = &out[..len];
191 
192                     if let Err(e) = socket.send_to(out, &src) {
193                         if e.kind() == std::io::ErrorKind::WouldBlock {
194                             debug!("send() would block");
195                             break;
196                         }
197 
198                         panic!("send() failed: {:?}", e);
199                     }
200                     continue 'read;
201                 }
202 
203                 let mut scid = [0; quiche::MAX_CONN_ID_LEN];
204                 scid.copy_from_slice(&conn_id);
205 
206                 // Token is always present in Initial packets.
207                 let token = hdr.token.as_ref().unwrap();
208 
209                 // Do stateless retry if the client didn't send a token.
210                 if token.is_empty() {
211                     warn!("Doing stateless retry");
212 
213                     let new_token = mint_token(&hdr, &src);
214 
215                     let len = quiche::retry(
216                         &hdr.scid,
217                         &hdr.dcid,
218                         &scid,
219                         &new_token,
220                         hdr.version,
221                         &mut out,
222                     )
223                     .unwrap();
224 
225                     let out = &out[..len];
226 
227                     if let Err(e) = socket.send_to(out, &src) {
228                         if e.kind() == std::io::ErrorKind::WouldBlock {
229                             debug!("send() would block");
230                             break;
231                         }
232 
233                         panic!("send() failed: {:?}", e);
234                     }
235                     continue 'read;
236                 }
237 
238                 let odcid = validate_token(&src, token);
239 
240                 // The token was not valid, meaning the retry failed, so
241                 // drop the packet.
242                 if odcid == None {
243                     error!("Invalid address validation token");
244                     continue 'read;
245                 }
246 
247                 if scid.len() != hdr.dcid.len() {
248                     error!("Invalid destination connection ID");
249                     continue 'read;
250                 }
251 
252                 // Reuse the source connection ID we sent in the Retry
253                 // packet, instead of changing it again.
254                 scid.copy_from_slice(&hdr.dcid);
255 
256                 debug!(
257                     "New connection: dcid={} scid={}",
258                     hex_dump(&hdr.dcid),
259                     hex_dump(&scid)
260                 );
261 
262                 let conn = quiche::accept(&scid, odcid, &mut config).unwrap();
263 
264                 let client = Client {
265                     conn,
266                     partial_responses: HashMap::new(),
267                 };
268 
269                 clients.insert(scid.to_vec(), (src, client));
270 
271                 clients.get_mut(&scid[..]).unwrap()
272             } else {
273                 match clients.get_mut(&hdr.dcid) {
274                     Some(v) => v,
275 
276                     None => clients.get_mut(conn_id).unwrap(),
277                 }
278             };
279 
280             // Process potentially coalesced packets.
281             let read = match client.conn.recv(pkt_buf) {
282                 Ok(v) => v,
283 
284                 Err(e) => {
285                     error!("{} recv failed: {:?}", client.conn.trace_id(), e);
286                     continue 'read;
287                 },
288             };
289 
290             debug!("{} processed {} bytes", client.conn.trace_id(), read);
291 
292             if client.conn.is_in_early_data() || client.conn.is_established() {
293                 // Handle writable streams.
294                 for stream_id in client.conn.writable() {
295                     handle_writable(client, stream_id);
296                 }
297 
298                 // Process all readable streams.
299                 for s in client.conn.readable() {
300                     while let Ok((read, fin)) =
301                         client.conn.stream_recv(s, &mut buf)
302                     {
303                         debug!(
304                             "{} received {} bytes",
305                             client.conn.trace_id(),
306                             read
307                         );
308 
309                         let stream_buf = &buf[..read];
310 
311                         debug!(
312                             "{} stream {} has {} bytes (fin? {})",
313                             client.conn.trace_id(),
314                             s,
315                             stream_buf.len(),
316                             fin
317                         );
318 
319                         handle_stream(client, s, stream_buf, "examples/root");
320                     }
321                 }
322             }
323         }
324 
325         // Generate outgoing QUIC packets for all active connections and send
326         // them on the UDP socket, until quiche reports that there are no more
327         // packets to be sent.
328         for (peer, client) in clients.values_mut() {
329             loop {
330                 let write = match client.conn.send(&mut out) {
331                     Ok(v) => v,
332 
333                     Err(quiche::Error::Done) => {
334                         debug!("{} done writing", client.conn.trace_id());
335                         break;
336                     },
337 
338                     Err(e) => {
339                         error!("{} send failed: {:?}", client.conn.trace_id(), e);
340 
341                         client.conn.close(false, 0x1, b"fail").ok();
342                         break;
343                     },
344                 };
345 
346                 // TODO: coalesce packets.
347                 if let Err(e) = socket.send_to(&out[..write], &peer) {
348                     if e.kind() == std::io::ErrorKind::WouldBlock {
349                         debug!("send() would block");
350                         break;
351                     }
352 
353                     panic!("send() failed: {:?}", e);
354                 }
355 
356                 debug!("{} written {} bytes", client.conn.trace_id(), write);
357             }
358         }
359 
360         // Garbage collect closed connections.
361         clients.retain(|_, (_, ref mut c)| {
362             debug!("Collecting garbage");
363 
364             if c.conn.is_closed() {
365                 info!(
366                     "{} connection collected {:?}",
367                     c.conn.trace_id(),
368                     c.conn.stats()
369                 );
370             }
371 
372             !c.conn.is_closed()
373         });
374     }
375 }
376 
377 /// Generate a stateless retry token.
378 ///
379 /// The token includes the static string `"quiche"` followed by the IP address
380 /// of the client and by the original destination connection ID generated by the
381 /// client.
382 ///
383 /// Note that this function is only an example and doesn't do any cryptographic
384 /// authenticate of the token. *It should not be used in production system*.
mint_token(hdr: &quiche::Header, src: &net::SocketAddr) -> Vec<u8>385 fn mint_token(hdr: &quiche::Header, src: &net::SocketAddr) -> Vec<u8> {
386     let mut token = Vec::new();
387 
388     token.extend_from_slice(b"quiche");
389 
390     let addr = match src.ip() {
391         std::net::IpAddr::V4(a) => a.octets().to_vec(),
392         std::net::IpAddr::V6(a) => a.octets().to_vec(),
393     };
394 
395     token.extend_from_slice(&addr);
396     token.extend_from_slice(&hdr.dcid);
397 
398     token
399 }
400 
401 /// Validates a stateless retry token.
402 ///
403 /// This checks that the ticket includes the `"quiche"` static string, and that
404 /// the client IP address matches the address stored in the ticket.
405 ///
406 /// Note that this function is only an example and doesn't do any cryptographic
407 /// authenticate of the token. *It should not be used in production system*.
validate_token<'a>( src: &net::SocketAddr, token: &'a [u8], ) -> Option<&'a [u8]>408 fn validate_token<'a>(
409     src: &net::SocketAddr, token: &'a [u8],
410 ) -> Option<&'a [u8]> {
411     if token.len() < 6 {
412         return None;
413     }
414 
415     if &token[..6] != b"quiche" {
416         return None;
417     }
418 
419     let token = &token[6..];
420 
421     let addr = match src.ip() {
422         std::net::IpAddr::V4(a) => a.octets().to_vec(),
423         std::net::IpAddr::V6(a) => a.octets().to_vec(),
424     };
425 
426     if token.len() < addr.len() || &token[..addr.len()] != addr.as_slice() {
427         return None;
428     }
429 
430     let token = &token[addr.len()..];
431 
432     Some(&token[..])
433 }
434 
435 /// Handles incoming HTTP/0.9 requests.
handle_stream(client: &mut Client, stream_id: u64, buf: &[u8], root: &str)436 fn handle_stream(client: &mut Client, stream_id: u64, buf: &[u8], root: &str) {
437     let conn = &mut client.conn;
438 
439     if buf.len() > 4 && &buf[..4] == b"GET " {
440         let uri = &buf[4..buf.len()];
441         let uri = String::from_utf8(uri.to_vec()).unwrap();
442         let uri = String::from(uri.lines().next().unwrap());
443         let uri = std::path::Path::new(&uri);
444         let mut path = std::path::PathBuf::from(root);
445 
446         for c in uri.components() {
447             if let std::path::Component::Normal(v) = c {
448                 path.push(v)
449             }
450         }
451 
452         info!(
453             "{} got GET request for {:?} on stream {}",
454             conn.trace_id(),
455             path,
456             stream_id
457         );
458 
459         let body = std::fs::read(path.as_path())
460             .unwrap_or_else(|_| b"Not Found!\r\n".to_vec());
461 
462         info!(
463             "{} sending response of size {} on stream {}",
464             conn.trace_id(),
465             body.len(),
466             stream_id
467         );
468 
469         let written = match conn.stream_send(stream_id, &body, true) {
470             Ok(v) => v,
471 
472             Err(quiche::Error::Done) => 0,
473 
474             Err(e) => {
475                 error!("{} stream send failed {:?}", conn.trace_id(), e);
476                 return;
477             },
478         };
479 
480         if written < body.len() {
481             let response = PartialResponse { body, written };
482             client.partial_responses.insert(stream_id, response);
483         }
484     }
485 }
486 
487 /// Handles newly writable streams.
handle_writable(client: &mut Client, stream_id: u64)488 fn handle_writable(client: &mut Client, stream_id: u64) {
489     let conn = &mut client.conn;
490 
491     debug!("{} stream {} is writable", conn.trace_id(), stream_id);
492 
493     if !client.partial_responses.contains_key(&stream_id) {
494         return;
495     }
496 
497     let resp = client.partial_responses.get_mut(&stream_id).unwrap();
498     let body = &resp.body[resp.written..];
499 
500     let written = match conn.stream_send(stream_id, &body, true) {
501         Ok(v) => v,
502 
503         Err(quiche::Error::Done) => 0,
504 
505         Err(e) => {
506             error!("{} stream send failed {:?}", conn.trace_id(), e);
507             return;
508         },
509     };
510 
511     resp.written += written;
512 
513     if resp.written == resp.body.len() {
514         client.partial_responses.remove(&stream_id);
515     }
516 }
517 
hex_dump(buf: &[u8]) -> String518 fn hex_dump(buf: &[u8]) -> String {
519     let vec: Vec<String> = buf.iter().map(|b| format!("{:02x}", b)).collect();
520 
521     vec.join("")
522 }
523