1use crate::request::normalise_name;
10
11pub const MAX_HELLO: usize = 64 * 1024;
15
16const RECORD_HEADER: usize = 5;
17const MAX_RECORD: usize = 16 * 1024 + 2048;
18const CONTENT_HANDSHAKE: u8 = 22;
19const HANDSHAKE_CLIENT_HELLO: u8 = 1;
20const EXT_SERVER_NAME: u16 = 0;
21const NAME_TYPE_HOST: u8 = 0;
22const EXT_ECH: u16 = 0xfe0d;
25const EXT_ESNI: u16 = 0xffce;
27
28#[derive(Debug, Clone, PartialEq, Eq)]
30pub enum Hello {
31 Incomplete,
33 ServerName(Option<String>),
35 Encrypted(Option<String>),
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
42#[non_exhaustive]
43pub enum HelloError {
44 #[error("the tunnel does not start with a TLS handshake")]
46 NotTls,
47 #[error("malformed TLS ClientHello")]
49 Malformed,
50 #[error("TLS ClientHello larger than {MAX_HELLO} bytes")]
52 TooLarge,
53}
54
55pub fn server_name(buf: &[u8]) -> Result<Hello, HelloError> {
57 let mut handshake = Vec::new();
58 let mut pos = 0;
59 loop {
60 let Some(&[content, major, _, len_hi, len_lo]) = buf.get(pos..pos + RECORD_HEADER) else {
61 return Ok(Hello::Incomplete);
62 };
63 if content != CONTENT_HANDSHAKE || major != 3 {
64 return Err(HelloError::NotTls);
65 }
66 let len = usize::from(u16::from_be_bytes([len_hi, len_lo]));
67 if len == 0 || len > MAX_RECORD {
68 return Err(HelloError::Malformed);
69 }
70 let start = pos + RECORD_HEADER;
71 let Some(fragment) = buf.get(start..start + len) else {
72 return Ok(Hello::Incomplete);
73 };
74 handshake.extend_from_slice(fragment);
75 pos = start + len;
76
77 if let Some(&[kind, len0, len1, len2]) = handshake.get(..4) {
78 if kind != HANDSHAKE_CLIENT_HELLO {
79 return Err(HelloError::Malformed);
80 }
81 let body_len = usize::from(len0) << 16 | usize::from(len1) << 8 | usize::from(len2);
82 if body_len > MAX_HELLO {
83 return Err(HelloError::TooLarge);
84 }
85 if let Some(body) = handshake.get(4..4 + body_len) {
86 return client_hello_sni(body).map(|(name, encrypted)| {
87 if encrypted {
88 Hello::Encrypted(name)
89 } else {
90 Hello::ServerName(name)
91 }
92 });
93 }
94 }
95 }
96}
97
98fn client_hello_sni(body: &[u8]) -> Result<(Option<String>, bool), HelloError> {
100 let mut r = Reader(body);
101 r.take(2 + 32)?; let session_id_len = r.u8()?;
103 r.take(session_id_len.into())?;
104 let suites_len = r.u16()?;
105 r.take(suites_len.into())?;
106 let compression_len = r.u8()?;
107 r.take(compression_len.into())?;
108 if r.0.is_empty() {
109 return Ok((None, false));
110 }
111 let ext_len = r.u16()?;
112 let mut exts = Reader(r.take(ext_len.into())?);
113 r.end()?;
114 let mut name = None;
115 let mut encrypted = false;
116 while !exts.0.is_empty() {
117 let kind = exts.u16()?;
118 let len = exts.u16()?;
119 let data = exts.take(len.into())?;
120 if kind == EXT_SERVER_NAME {
121 if name.is_some() {
122 return Err(HelloError::Malformed);
123 }
124 name = Some(server_name_list(data)?);
125 }
126 encrypted |= kind == EXT_ECH || kind == EXT_ESNI;
127 }
128 Ok((name.flatten(), encrypted))
129}
130
131fn server_name_list(data: &[u8]) -> Result<Option<String>, HelloError> {
133 let mut r = Reader(data);
134 let list_len = r.u16()?;
135 let mut list = Reader(r.take(list_len.into())?);
136 r.end()?;
137 let mut host = None;
138 while !list.0.is_empty() {
139 let kind = list.u8()?;
140 let len = list.u16()?;
141 let value = list.take(len.into())?;
142 if kind != NAME_TYPE_HOST {
143 continue;
144 }
145 if host.is_some() {
146 return Err(HelloError::Malformed);
147 }
148 let name = std::str::from_utf8(value)
151 .ok()
152 .and_then(normalise_name)
153 .ok_or(HelloError::Malformed)?;
154 host = Some(name);
155 }
156 Ok(host)
157}
158
159struct Reader<'a>(&'a [u8]);
161
162impl<'a> Reader<'a> {
163 fn take(&mut self, n: usize) -> Result<&'a [u8], HelloError> {
164 let (head, rest) = self.0.split_at_checked(n).ok_or(HelloError::Malformed)?;
165 self.0 = rest;
166 Ok(head)
167 }
168
169 fn array<const N: usize>(&mut self) -> Result<[u8; N], HelloError> {
170 let (head, rest) = self.0.split_first_chunk().ok_or(HelloError::Malformed)?;
171 self.0 = rest;
172 Ok(*head)
173 }
174
175 fn u8(&mut self) -> Result<u8, HelloError> {
176 let [b] = self.array()?;
177 Ok(b)
178 }
179
180 fn u16(&mut self) -> Result<u16, HelloError> {
181 self.array().map(u16::from_be_bytes)
182 }
183
184 fn end(&self) -> Result<(), HelloError> {
185 if self.0.is_empty() {
186 Ok(())
187 } else {
188 Err(HelloError::Malformed)
189 }
190 }
191}
192
193#[cfg(test)]
194mod tests;