1use bytes::BufMut;
12use nom::{IResult, bytes::streaming::take, number::streaming::be_u32};
13
14#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct ResponseRecord {
17 pub dns: Vec<u8>,
19 pub cert: Vec<u8>,
21}
22
23impl ResponseRecord {
24 pub fn cert_fingerprint_hex(&self) -> Option<String> {
27 if self.cert.is_empty() {
28 return None;
29 }
30 use ring::digest::{SHA256, digest};
31 let digest = digest(&SHA256, &self.cert);
32 Some(digest.as_ref().iter().map(|b| format!("{b:02x}")).collect())
33 }
34}
35
36#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct MultiResponse {
39 pub records: Vec<ResponseRecord>,
40}
41
42impl MultiResponse {
43 pub fn new(iter: impl IntoIterator<Item = (Vec<u8>, Vec<u8>)>) -> Self {
44 Self {
45 records: iter
46 .into_iter()
47 .map(|(dns, cert)| ResponseRecord { dns, cert })
48 .collect(),
49 }
50 }
51
52 pub fn encoding_size(&self) -> usize {
53 4 + self
54 .records
55 .iter()
56 .map(|record| 4 + record.dns.len() + 4 + record.cert.len())
57 .sum::<usize>()
58 }
59
60 pub fn encode(&self) -> Vec<u8> {
61 let mut buf = Vec::with_capacity(self.encoding_size());
62 buf.put_multi_response(self);
63 buf
64 }
65}
66
67pub trait WriteMultiResponse {
68 fn put_multi_response(&mut self, response: &MultiResponse);
69}
70
71impl<B: BufMut> WriteMultiResponse for B {
72 fn put_multi_response(&mut self, response: &MultiResponse) {
73 self.put_u32(response.records.len() as u32);
74 for record in &response.records {
75 self.put_u32(record.dns.len() as u32);
76 self.put_slice(&record.dns);
77 self.put_u32(record.cert.len() as u32);
78 self.put_slice(&record.cert);
79 }
80 }
81}
82
83pub fn be_multi_response(input: &[u8]) -> IResult<&[u8], MultiResponse> {
84 let (mut input, count) = be_u32(input)?;
85 let mut records = Vec::with_capacity(count as usize);
86 for _ in 0..count {
87 let (rest, dns_len) = be_u32(input)?;
88 let (rest, dns) = take(dns_len as usize)(rest)?;
89 let (rest, cert_len) = be_u32(rest)?;
90 let (rest, cert) = take(cert_len as usize)(rest)?;
91 records.push(ResponseRecord {
92 dns: dns.to_vec(),
93 cert: cert.to_vec(),
94 });
95 input = rest;
96 }
97 Ok((input, MultiResponse { records }))
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn multi_response_roundtrips() {
106 let response =
107 MultiResponse::new([(vec![1, 2, 3], vec![4, 5]), (vec![6, 7, 8, 9], Vec::new())]);
108 let encoded = response.encode();
109 let (remain, decoded) = be_multi_response(&encoded).unwrap();
110 assert!(remain.is_empty());
111 assert_eq!(decoded, response);
112 }
113}