wireforge_app/smb2/
negotiate.rs1pub struct Smb2NegotiateRequest<'a> { buf: &'a [u8] }
4
5impl<'a> Smb2NegotiateRequest<'a> {
6 pub fn parse(buf: &'a [u8]) -> Option<Self> {
7 if buf.len() < 36 { return None; }
10 if u16::from_le_bytes([buf[0], buf[1]]) != 36 { return None; }
11 Some(Self { buf })
12 }
13
14 pub fn dialect_count(&self) -> u16 {
15 u16::from_le_bytes([self.buf[2], self.buf[3]])
16 }
17
18 pub fn capabilities(&self) -> u32 {
19 u32::from_le_bytes([self.buf[8], self.buf[9], self.buf[10], self.buf[11]])
20 }
21
22 pub fn client_guid(&self) -> &[u8; 16] {
24 self.buf[12..28].try_into().unwrap()
25 }
26
27 pub fn dialects(&self) -> Vec<u16> {
29 let cnt = self.dialect_count() as usize;
30 (0..cnt)
31 .filter_map(|i| {
32 let off = 36 + i * 2;
33 if off + 2 <= self.buf.len() {
34 Some(u16::from_le_bytes([self.buf[off], self.buf[off + 1]]))
35 } else {
36 None
37 }
38 })
39 .collect()
40 }
41}
42
43pub struct Smb2NegotiateResponse<'a> { buf: &'a [u8] }
44
45impl<'a> Smb2NegotiateResponse<'a> {
46 pub fn parse(buf: &'a [u8]) -> Option<Self> {
47 if buf.len() < 65 { return None; }
52 if u16::from_le_bytes([buf[0], buf[1]]) != 65 { return None; }
53 Some(Self { buf })
54 }
55
56 pub fn dialect_revision(&self) -> u16 {
57 u16::from_le_bytes([self.buf[4], self.buf[5]])
58 }
59
60 pub fn server_guid(&self) -> &[u8; 16] {
61 self.buf[8..24].try_into().unwrap()
62 }
63
64 pub fn capabilities(&self) -> u32 {
65 u32::from_le_bytes([self.buf[24], self.buf[25], self.buf[26], self.buf[27]])
66 }
67
68 pub fn max_transact_size(&self) -> u32 {
69 u32::from_le_bytes([self.buf[28], self.buf[29], self.buf[30], self.buf[31]])
70 }
71
72 pub fn max_read_size(&self) -> u32 {
73 u32::from_le_bytes([self.buf[32], self.buf[33], self.buf[34], self.buf[35]])
74 }
75
76 pub fn max_write_size(&self) -> u32 {
77 u32::from_le_bytes([self.buf[36], self.buf[37], self.buf[38], self.buf[39]])
78 }
79
80 pub fn system_time(&self) -> u64 {
81 u64::from_le_bytes([
82 self.buf[40], self.buf[41], self.buf[42], self.buf[43],
83 self.buf[44], self.buf[45], self.buf[46], self.buf[47],
84 ])
85 }
86
87 pub fn server_start_time(&self) -> u64 {
88 u64::from_le_bytes([
89 self.buf[48], self.buf[49], self.buf[50], self.buf[51],
90 self.buf[52], self.buf[53], self.buf[54], self.buf[55],
91 ])
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn parse_negotiate_request() {
101 let mut body = vec![36u8, 0, 4, 0, 0, 0, 0, 0]; body.extend_from_slice(&1u32.to_le_bytes()); body.extend_from_slice(&[0xAAu8; 16]); body.extend_from_slice(&0u64.to_le_bytes()); body.extend_from_slice(&0x0202u16.to_le_bytes()); body.extend_from_slice(&0x0210u16.to_le_bytes());
107 body.extend_from_slice(&0x0300u16.to_le_bytes());
108 body.extend_from_slice(&0x0311u16.to_le_bytes());
109 let req = Smb2NegotiateRequest::parse(&body).unwrap();
110 assert_eq!(req.dialect_count(), 4);
111 assert_eq!(req.dialects(), vec![0x0202, 0x0210, 0x0300, 0x0311]);
112 }
113
114 #[test]
115 fn parse_negotiate_response() {
116 let mut body = vec![65u8, 0, 0, 0, 0x11, 0x03, 0, 0]; body.extend_from_slice(&[0u8; 16]); body.extend_from_slice(&0u32.to_le_bytes()); body.extend_from_slice(&65536u32.to_le_bytes()); body.extend_from_slice(&65536u32.to_le_bytes()); body.extend_from_slice(&65536u32.to_le_bytes()); body.extend_from_slice(&0u64.to_le_bytes()); body.extend_from_slice(&0u64.to_le_bytes()); body.extend_from_slice(&[0u8; 9]); let resp = Smb2NegotiateResponse::parse(&body).unwrap();
126 assert_eq!(resp.dialect_revision(), 0x0311);
127 assert_eq!(resp.max_read_size(), 65536);
128 }
129}