• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //! Client management, including the communication with quiche I/O.
18 
19 use anyhow::{anyhow, bail, ensure, Result};
20 use log::{debug, error, info, warn};
21 use quiche::h3::NameValue;
22 use ring::hmac;
23 use ring::rand::SystemRandom;
24 use std::collections::{hash_map, HashMap};
25 use std::net::SocketAddr;
26 use std::pin::Pin;
27 use std::time::Duration;
28 
29 pub const DNS_HEADER_SIZE: usize = 12;
30 pub const MAX_UDP_PAYLOAD_SIZE: usize = 1350;
31 
32 pub type ConnectionID = Vec<u8>;
33 
34 const URL_PATH_PREFIX: &str = "/dns-query?dns=";
35 
36 /// Manages a QUIC and HTTP/3 connection. No socket I/O operations.
37 pub struct Client {
38     /// QUIC connection.
39     conn: Pin<Box<quiche::Connection>>,
40 
41     /// HTTP/3 connection.
42     h3_conn: Option<quiche::h3::Connection>,
43 
44     /// Socket address the client from.
45     addr: SocketAddr,
46 
47     /// The unique ID for the client.
48     id: ConnectionID,
49 
50     /// Queues the DNS queries being processed in backend.
51     /// <Query ID, Stream ID>
52     in_flight_queries: HashMap<[u8; 2], u64>,
53 
54     /// Queues the second part DNS answers needed to be sent after first part.
55     /// <Stream ID, ans>
56     pending_answers: Vec<(u64, Vec<u8>)>,
57 }
58 
59 impl Client {
new(conn: Pin<Box<quiche::Connection>>, addr: &SocketAddr, id: ConnectionID) -> Client60     fn new(conn: Pin<Box<quiche::Connection>>, addr: &SocketAddr, id: ConnectionID) -> Client {
61         Client {
62             conn,
63             h3_conn: None,
64             addr: *addr,
65             id,
66             in_flight_queries: HashMap::new(),
67             pending_answers: Vec::new(),
68         }
69     }
70 
create_http3_connection(&mut self) -> Result<()>71     fn create_http3_connection(&mut self) -> Result<()> {
72         ensure!(self.h3_conn.is_none(), "HTTP/3 connection is already created");
73 
74         let config = quiche::h3::Config::new()?;
75         let conn = quiche::h3::Connection::with_transport(&mut self.conn, &config)?;
76         self.h3_conn = Some(conn);
77         Ok(())
78     }
79 
80     // Processes HTTP/3 request and returns the wire format DNS query or an empty vector.
handle_http3_request(&mut self) -> Result<Vec<u8>>81     fn handle_http3_request(&mut self) -> Result<Vec<u8>> {
82         ensure!(self.h3_conn.is_some(), "HTTP/3 connection not created");
83 
84         let h3_conn = self.h3_conn.as_mut().unwrap();
85         let mut ret = vec![];
86 
87         loop {
88             match h3_conn.poll(&mut self.conn) {
89                 Ok((stream_id, quiche::h3::Event::Headers { list, has_body })) => {
90                     info!(
91                         "Processing HTTP/3 Headers {:?} on stream id {} has_body {}",
92                         list, stream_id, has_body
93                     );
94 
95                     // Find ":path" field to get the query.
96                     if let Some(target) = list.iter().find(|e| {
97                         e.name() == b":path" && e.value().starts_with(URL_PATH_PREFIX.as_bytes())
98                     }) {
99                         let b64url_query = &target.value()[URL_PATH_PREFIX.len()..];
100                         let decoded = base64::decode_config(b64url_query, base64::URL_SAFE_NO_PAD)?;
101                         self.in_flight_queries.insert([decoded[0], decoded[1]], stream_id);
102                         ret = decoded;
103                     }
104                 }
105                 Ok((stream_id, quiche::h3::Event::Data)) => {
106                     warn!("Received unexpected HTTP/3 data");
107                     let mut buf = [0; 65535];
108                     if let Ok(read) = h3_conn.recv_body(&mut self.conn, stream_id, &mut buf) {
109                         warn!("Got {} bytes of response data on stream {}", read, stream_id);
110                     }
111                 }
112                 Ok(n) => {
113                     debug!("Got event {:?}", n);
114                 }
115                 Err(quiche::h3::Error::Done) => {
116                     debug!("quiche::h3::Error::Done");
117                     break;
118                 }
119                 Err(e) => bail!("HTTP/3 processing failed: {:?}", e),
120             }
121         }
122 
123         Ok(ret)
124     }
125 
126     // Converts the clear-text DNS response to a DoH response, and sends it to the quiche.
handle_backend_message(&mut self, response: &[u8]) -> Result<()>127     pub fn handle_backend_message(&mut self, response: &[u8]) -> Result<()> {
128         ensure!(self.h3_conn.is_some(), "HTTP/3 connection not created");
129         ensure!(response.len() >= DNS_HEADER_SIZE, "Insufficient bytes of DNS response");
130 
131         let len = response.len();
132         let headers = vec![
133             quiche::h3::Header::new(b":status", b"200"),
134             quiche::h3::Header::new(b"content-type", b"application/dns-message"),
135             quiche::h3::Header::new(b"content-length", len.to_string().as_bytes()),
136             // TODO: need to add cache-control?
137         ];
138 
139         let h3_conn = self.h3_conn.as_mut().unwrap();
140         let query_id = u16::from_be_bytes([response[0], response[1]]);
141         let stream_id = self
142             .in_flight_queries
143             .remove(&[response[0], response[1]])
144             .ok_or_else(|| anyhow!("query_id {:x} not found", query_id))?;
145 
146         info!("Preparing HTTP/3 response {:?} on stream {}", headers, stream_id);
147 
148         h3_conn.send_response(&mut self.conn, stream_id, &headers, false)?;
149 
150         // In order to simulate the case that server send multiple packets for a DNS answer,
151         // only send half of the answer here. The remaining one will be cached here and then
152         // processed later in process_pending_answers().
153         let (first, second) = response.split_at(len / 2);
154         h3_conn.send_body(&mut self.conn, stream_id, first, false)?;
155         self.pending_answers.push((stream_id, second.to_vec()));
156 
157         Ok(())
158     }
159 
process_pending_answers(&mut self) -> Result<()>160     pub fn process_pending_answers(&mut self) -> Result<()> {
161         if let Some((stream_id, ans)) = self.pending_answers.pop() {
162             let h3_conn = self.h3_conn.as_mut().unwrap();
163             info!("process the remaining response for stream {}", stream_id);
164             h3_conn.send_body(&mut self.conn, stream_id, &ans, true)?;
165         }
166         Ok(())
167     }
168 
169     // Returns the data the client wants to send.
flush_egress(&mut self) -> Result<Vec<u8>>170     pub fn flush_egress(&mut self) -> Result<Vec<u8>> {
171         let mut ret = vec![];
172         let mut buf = [0; MAX_UDP_PAYLOAD_SIZE];
173 
174         let (write, _) = match self.conn.send(&mut buf) {
175             Ok(v) => v,
176             Err(quiche::Error::Done) => bail!(quiche::Error::Done),
177             Err(e) => {
178                 error!("flush_egress failed: {}", e);
179                 bail!(e)
180             }
181         };
182         ret.append(&mut buf[..write].to_vec());
183 
184         Ok(ret)
185     }
186 
187     // Processes the packet received from the frontend socket. If |data| is a DoH query,
188     // the function returns the wire format DNS query; otherwise, it returns empty vector.
handle_frontend_message(&mut self, data: &mut [u8]) -> Result<Vec<u8>>189     pub fn handle_frontend_message(&mut self, data: &mut [u8]) -> Result<Vec<u8>> {
190         let recv_info = quiche::RecvInfo { from: self.addr };
191         self.conn.recv(data, recv_info)?;
192 
193         if (self.conn.is_in_early_data() || self.conn.is_established()) && self.h3_conn.is_none() {
194             // Create a HTTP3 connection as soon as the QUIC connection is established.
195             self.create_http3_connection()?;
196             info!("HTTP/3 connection created");
197         }
198 
199         if self.h3_conn.is_some() {
200             return self.handle_http3_request();
201         }
202 
203         Ok(vec![])
204     }
205 
is_waiting_for_query(&self, query_id: &[u8; 2]) -> bool206     pub fn is_waiting_for_query(&self, query_id: &[u8; 2]) -> bool {
207         self.in_flight_queries.contains_key(query_id)
208     }
209 
addr(&self) -> SocketAddr210     pub fn addr(&self) -> SocketAddr {
211         self.addr
212     }
213 
connection_id(&self) -> &ConnectionID214     pub fn connection_id(&self) -> &ConnectionID {
215         self.id.as_ref()
216     }
217 
timeout(&self) -> Option<Duration>218     pub fn timeout(&self) -> Option<Duration> {
219         self.conn.timeout()
220     }
221 
on_timeout(&mut self)222     pub fn on_timeout(&mut self) {
223         self.conn.on_timeout();
224     }
225 
is_alive(&self) -> bool226     pub fn is_alive(&self) -> bool {
227         self.conn.is_established() && !self.conn.is_closed()
228     }
229 
is_resumed(&self) -> bool230     pub fn is_resumed(&self) -> bool {
231         self.conn.is_resumed()
232     }
233 
close(&mut self)234     pub fn close(&mut self) {
235         let _ = self.conn.close(false, 0, b"Graceful shutdown");
236     }
237 }
238 
239 impl std::fmt::Debug for Client {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result240     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
241         f.debug_struct("Client")
242             .field("addr", &self.addr())
243             .field("conn_id", &self.conn.trace_id())
244             .finish()
245     }
246 }
247 
248 pub struct ClientMap {
249     clients: HashMap<ConnectionID, Client>,
250     conn_id_seed: hmac::Key,
251     config: quiche::Config,
252 }
253 
254 impl ClientMap {
new(config: quiche::Config) -> Result<ClientMap>255     pub fn new(config: quiche::Config) -> Result<ClientMap> {
256         let conn_id_seed = match hmac::Key::generate(hmac::HMAC_SHA256, &SystemRandom::new()) {
257             Ok(v) => v,
258             Err(e) => bail!("Failed to generate a seed: {}", e),
259         };
260 
261         Ok(ClientMap { clients: HashMap::new(), conn_id_seed, config })
262     }
263 
get_or_create( &mut self, hdr: &quiche::Header, addr: &SocketAddr, ) -> Result<&mut Client>264     pub fn get_or_create(
265         &mut self,
266         hdr: &quiche::Header,
267         addr: &SocketAddr,
268     ) -> Result<&mut Client> {
269         let dcid = hdr.dcid.as_ref().to_vec();
270         let client = if !self.clients.contains_key(&dcid) {
271             ensure!(hdr.ty == quiche::Type::Initial, "Packet is not Initial");
272             ensure!(quiche::version_is_supported(hdr.version), "Protocol version not supported");
273 
274             let scid = generate_conn_id(&self.conn_id_seed, &dcid);
275             let conn = quiche::accept(
276                 &quiche::ConnectionId::from_ref(&scid),
277                 None, /* odcid */
278                 *addr,
279                 &mut self.config,
280             )?;
281             let client = Client::new(conn, addr, scid.clone());
282 
283             info!("New client: {:?}", client);
284             self.clients.insert(scid.clone(), client);
285             self.clients.get_mut(&scid).unwrap()
286         } else {
287             self.clients.get_mut(&dcid).unwrap()
288         };
289 
290         Ok(client)
291     }
292 
get_mut(&mut self, id: &[u8]) -> Option<&mut Client>293     pub fn get_mut(&mut self, id: &[u8]) -> Option<&mut Client> {
294         self.clients.get_mut(&id.to_vec())
295     }
296 
iter_mut(&mut self) -> hash_map::IterMut<ConnectionID, Client>297     pub fn iter_mut(&mut self) -> hash_map::IterMut<ConnectionID, Client> {
298         self.clients.iter_mut()
299     }
300 
iter(&mut self) -> hash_map::Iter<ConnectionID, Client>301     pub fn iter(&mut self) -> hash_map::Iter<ConnectionID, Client> {
302         self.clients.iter()
303     }
304 
len(&mut self) -> usize305     pub fn len(&mut self) -> usize {
306         self.clients.len()
307     }
308 }
309 
generate_conn_id(conn_id_seed: &hmac::Key, dcid: &[u8]) -> ConnectionID310 fn generate_conn_id(conn_id_seed: &hmac::Key, dcid: &[u8]) -> ConnectionID {
311     let conn_id = hmac::sign(conn_id_seed, dcid);
312     let conn_id = &conn_id.as_ref()[..quiche::MAX_CONN_ID_LEN];
313     conn_id.to_vec()
314 }
315