1use super::super::packet::header::{
4 QuicConnectionId, QuicConnectionIdField, QuicLongHeader, QuicLongPacketType, QuicVersion,
5};
6use super::super::packet::terminal::{QuicRetryPacket, QuicVersionNegotiationPacket};
7use super::QuicPacketBuildError;
8
9const RETRY_INTEGRITY_TAG_LEN: usize = 16;
10
11pub struct QuicVersionNegotiationPacketBuilder<'buffer, 'input> {
13 destination: &'buffer mut [u8],
14 unused_bits: u8,
15 destination_connection_id: QuicConnectionId<'input>,
16 source_connection_id: QuicConnectionId<'input>,
17 versions: &'input [QuicVersion],
18}
19
20impl<'buffer, 'input> QuicVersionNegotiationPacketBuilder<'buffer, 'input> {
21 pub fn new(
23 destination: &'buffer mut [u8],
24 unused_bits: u8,
25 destination_connection_id: QuicConnectionId<'input>,
26 source_connection_id: QuicConnectionId<'input>,
27 versions: &'input [QuicVersion],
28 ) -> Self {
29 Self {
30 destination,
31 unused_bits,
32 destination_connection_id,
33 source_connection_id,
34 versions,
35 }
36 }
37
38 pub fn build(self) -> Result<QuicVersionNegotiationPacket<'buffer>, QuicPacketBuildError> {
40 if self.unused_bits > 0x7f {
41 return Err(QuicPacketBuildError::UnusedBitsOutOfRange {
42 maximum: 0x7f,
43 actual: self.unused_bits,
44 });
45 }
46 validate_connection_id(
47 QuicConnectionIdField::Destination,
48 self.destination_connection_id.len(),
49 255,
50 )?;
51 validate_connection_id(
52 QuicConnectionIdField::Source,
53 self.source_connection_id.len(),
54 255,
55 )?;
56 if self.versions.is_empty() {
57 return Err(QuicPacketBuildError::EmptyVersionList);
58 }
59
60 let version_bytes =
61 self.versions
62 .len()
63 .checked_mul(4)
64 .ok_or(QuicPacketBuildError::LengthOverflow {
65 component: "version list",
66 offset: self.versions.len(),
67 length: 4,
68 })?;
69 let destination_start = 6;
70 let destination_end = checked_add(
71 destination_start,
72 self.destination_connection_id.len(),
73 "destination connection ID",
74 )?;
75 let source_length_offset = destination_end;
76 let source_start = checked_add(source_length_offset, 1, "source connection ID length")?;
77 let source_end = checked_add(
78 source_start,
79 self.source_connection_id.len(),
80 "source connection ID",
81 )?;
82 let required = checked_add(source_end, version_bytes, "version list")?;
83 if self.destination.len() < required {
84 return Err(QuicPacketBuildError::BufferTooShort {
85 required,
86 available: self.destination.len(),
87 });
88 }
89
90 let destination = self.destination;
91 destination[0] = 0x80 | self.unused_bits;
92 destination[1..5].copy_from_slice(&QuicVersion::NEGOTIATION.raw().to_be_bytes());
93 destination[5] = self.destination_connection_id.len() as u8;
94 destination[destination_start..destination_end]
95 .copy_from_slice(self.destination_connection_id.as_bytes());
96 destination[source_length_offset] = self.source_connection_id.len() as u8;
97 destination[source_start..source_end].copy_from_slice(self.source_connection_id.as_bytes());
98 for (slot, version) in destination[source_end..required]
99 .chunks_exact_mut(4)
100 .zip(self.versions)
101 {
102 slot.copy_from_slice(&version.raw().to_be_bytes());
103 }
104
105 let bytes = &destination[..required];
106 let header = QuicLongHeader::from_validated(
107 &bytes[..source_end],
108 bytes[0],
109 QuicVersion::NEGOTIATION,
110 QuicConnectionId::new(&bytes[destination_start..destination_end]),
111 QuicConnectionId::new(&bytes[source_start..source_end]),
112 &bytes[source_end..],
113 );
114 Ok(QuicVersionNegotiationPacket::from_validated(
115 bytes,
116 header,
117 &bytes[source_end..],
118 ))
119 }
120}
121
122pub struct QuicRetryPacketBuilder<'buffer, 'input> {
124 destination: &'buffer mut [u8],
125 version: QuicVersion,
126 unused_bits: u8,
127 destination_connection_id: QuicConnectionId<'input>,
128 source_connection_id: QuicConnectionId<'input>,
129 token: &'input [u8],
130 integrity_tag: &'input [u8; RETRY_INTEGRITY_TAG_LEN],
131}
132
133impl<'buffer, 'input> QuicRetryPacketBuilder<'buffer, 'input> {
134 pub fn new(
136 destination: &'buffer mut [u8],
137 version: QuicVersion,
138 unused_bits: u8,
139 destination_connection_id: QuicConnectionId<'input>,
140 source_connection_id: QuicConnectionId<'input>,
141 token: &'input [u8],
142 integrity_tag: &'input [u8; RETRY_INTEGRITY_TAG_LEN],
143 ) -> Self {
144 Self {
145 destination,
146 version,
147 unused_bits,
148 destination_connection_id,
149 source_connection_id,
150 token,
151 integrity_tag,
152 }
153 }
154
155 pub fn build(self) -> Result<QuicRetryPacket<'buffer>, QuicPacketBuildError> {
157 let raw_type = match QuicLongPacketType::Retry.raw_type(self.version) {
158 Some(raw_type) => raw_type,
159 None => {
160 return Err(QuicPacketBuildError::UnsupportedVersion {
161 version: self.version,
162 });
163 }
164 };
165 if self.unused_bits > 0x0f {
166 return Err(QuicPacketBuildError::UnusedBitsOutOfRange {
167 maximum: 0x0f,
168 actual: self.unused_bits,
169 });
170 }
171 validate_connection_id(
172 QuicConnectionIdField::Destination,
173 self.destination_connection_id.len(),
174 20,
175 )?;
176 validate_connection_id(
177 QuicConnectionIdField::Source,
178 self.source_connection_id.len(),
179 20,
180 )?;
181 if self.token.is_empty() {
182 return Err(QuicPacketBuildError::EmptyRetryToken);
183 }
184
185 let destination_start = 6;
186 let destination_end = checked_add(
187 destination_start,
188 self.destination_connection_id.len(),
189 "destination connection ID",
190 )?;
191 let source_length_offset = destination_end;
192 let source_start = checked_add(source_length_offset, 1, "source connection ID length")?;
193 let source_end = checked_add(
194 source_start,
195 self.source_connection_id.len(),
196 "source connection ID",
197 )?;
198 let token_end = checked_add(source_end, self.token.len(), "Retry Token")?;
199 let required = checked_add(token_end, RETRY_INTEGRITY_TAG_LEN, "Retry Integrity Tag")?;
200 if self.destination.len() < required {
201 return Err(QuicPacketBuildError::BufferTooShort {
202 required,
203 available: self.destination.len(),
204 });
205 }
206
207 let destination = self.destination;
208 destination[0] = 0xc0 | (raw_type << 4) | self.unused_bits;
209 destination[1..5].copy_from_slice(&self.version.raw().to_be_bytes());
210 destination[5] = self.destination_connection_id.len() as u8;
211 destination[destination_start..destination_end]
212 .copy_from_slice(self.destination_connection_id.as_bytes());
213 destination[source_length_offset] = self.source_connection_id.len() as u8;
214 destination[source_start..source_end].copy_from_slice(self.source_connection_id.as_bytes());
215 destination[source_end..token_end].copy_from_slice(self.token);
216 destination[token_end..required].copy_from_slice(self.integrity_tag);
217
218 let bytes = &destination[..required];
219 let header = QuicLongHeader::from_validated(
220 &bytes[..source_end],
221 bytes[0],
222 self.version,
223 QuicConnectionId::new(&bytes[destination_start..destination_end]),
224 QuicConnectionId::new(&bytes[source_start..source_end]),
225 &bytes[source_end..],
226 );
227 Ok(QuicRetryPacket::from_validated(
228 bytes,
229 header,
230 QuicLongPacketType::Retry,
231 &bytes[source_end..token_end],
232 &bytes[token_end..],
233 ))
234 }
235}
236
237fn validate_connection_id(
238 field: QuicConnectionIdField,
239 actual: usize,
240 maximum: usize,
241) -> Result<(), QuicPacketBuildError> {
242 if actual > maximum {
243 return Err(QuicPacketBuildError::ConnectionIdTooLong {
244 field,
245 maximum,
246 actual,
247 });
248 }
249 Ok(())
250}
251
252fn checked_add(
253 offset: usize,
254 length: usize,
255 component: &'static str,
256) -> Result<usize, QuicPacketBuildError> {
257 offset
258 .checked_add(length)
259 .ok_or(QuicPacketBuildError::LengthOverflow {
260 component,
261 offset,
262 length,
263 })
264}