netbios_parser/
nbss_parser.rs1use crate::error::*;
2use crate::nbss_types::*;
3use crate::nom;
4use dns_parser::Name;
5use nom::error::ParseError;
6use nom::multi::count;
7use nom::number::streaming::{be_u16, be_u32, be_u8};
8use nom::{bytes::streaming::take, IResult};
9use nom_derive::Parse;
10use std::net::Ipv4Addr;
11
12pub(crate) fn be_u48<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], u64, E> {
13 let (i, hb) = be_u32(i)?;
14 let (i, lb) = be_u16(i)?;
15 let n = ((hb as u64) << 16) | (lb as u64);
16 Ok((i, n))
17}
18
19pub fn parse_nbss_header(i: &[u8]) -> Result<NbssHeader> {
21 let (rem, bytes) = take(NbssHeader::size())(i)?;
22 let name_trn_id = ((bytes[0] as u16) << 8) + (bytes[1]) as u16;
23 let fields_16_32 = ((bytes[2] as u16) << 8) + (bytes[3] as u16);
24 let qdcount = ((bytes[4] as u16) << 8) + (bytes[5] as u16);
25 let ancount = ((bytes[6] as u16) << 8) + (bytes[7] as u16);
26 let nscount = ((bytes[8] as u16) << 8) + (bytes[9] as u16);
27 let arcount = ((bytes[10] as u16) << 8) + (bytes[11] as u16);
28 Ok((
29 rem,
30 NbssHeader {
31 name_trn_id,
32 fields_16_32,
33 qdcount,
34 ancount,
35 nscount,
36 arcount,
37 },
38 ))
39}
40
41fn parse_node_name(i: &[u8]) -> Result<NodeName> {
42 let (rem, b) = take(16usize)(i)?;
43 let s = std::string::String::from_utf8_lossy(b);
44 let name = NetbiosName::from_bytes(s.as_bytes())?;
45 let (rem, name_flags) = be_u16(rem)?;
46 Ok((rem, NodeName { name, name_flags }))
47}
48
49fn parse_rdata(b: &[u8], rtype: RType) -> Result<RData> {
50 match rtype {
51 RType::NB => {
52 let (rem, nb_flags) = be_u16(b)?;
53 let (rem, addr) = take(4usize)(rem)?;
54 let nb_address = Ipv4Addr::new(addr[0], addr[1], addr[2], addr[3]);
55 Ok((
56 rem,
57 RData::NB {
58 nb_flags,
59 nb_address,
60 },
61 ))
62 }
63 RType::NBSTAT => {
64 let (d, num_names) = be_u8(b)?;
66 let (rem, names) = count(parse_node_name, num_names as usize)(d)?;
67 let (rem, stats) = NodeStatistics::parse(rem)?;
68 Ok((rem, RData::NBStat { names, stats }))
69 }
70 _ => Ok((&[], RData::Unknown(b))),
71 }
72}
73
74pub fn parse_nbss_packet(i: &[u8]) -> Result<NbssPacket> {
76 let original_data = i;
77 let (_, header) = parse_nbss_header(i)?;
78 let mut offset = NbssHeader::size();
79 let num_questions = header.qdcount as usize;
80 let mut questions = Vec::new();
82 for _ in 0..num_questions {
83 let name = Name::scan(&original_data[offset..], original_data)
84 .map_err(|_| NetbiosError::InvalidQuestion)?;
85 offset += name.byte_len();
86 let qname = EncodedName(name.to_string());
87 let (rem, qtype) = QType::parse(&original_data[offset..])?;
88 let (_, qclass) = RClass::parse(rem)?;
89 offset += 4;
90 let q = NetbiosQuestion {
91 qname,
92 qtype,
93 qclass,
94 };
95 questions.push(q);
96 }
97 let (_, rr_answer) =
98 parse_resource_records(header.ancount as usize, original_data, &mut offset)?;
99 let (_, rr_authority) =
100 parse_resource_records(header.nscount as usize, original_data, &mut offset)?;
101 let (_, rr_additional) =
102 parse_resource_records(header.arcount as usize, original_data, &mut offset)?;
103 Ok((
104 &original_data[offset..],
105 NbssPacket {
106 header,
107 questions,
108 rr_answer,
109 rr_authority,
110 rr_additional,
111 },
112 ))
113}
114
115fn parse_resource_records<'a>(
116 num_records: usize,
117 original_data: &'a [u8],
118 offset: &'_ mut usize,
119) -> Result<'a, Vec<NetbiosResource<'a>>> {
120 let mut resources = Vec::new();
121 for _ in 0..num_records {
122 let name = Name::scan(&original_data[*offset..], original_data)
123 .map_err(|_| NetbiosError::InvalidAnswer)?;
124 *offset += name.byte_len();
125 let rr_name = EncodedName(name.to_string());
126 let data = &original_data[*offset..];
127 let (rem, rr_type) = RType::parse(data)?;
128 let (rem, rr_class) = RClass::parse(rem)?;
129 let (rem, ttl) = be_u32(rem)?;
130 let (rem, rd_length) = be_u16(rem)?;
131 let (_, b) = take(rd_length as usize)(rem)?;
132 let (_, rdata) = parse_rdata(b, rr_type)?;
133 *offset += (10 + rd_length) as usize;
134 let r = NetbiosResource {
135 rr_name,
136 rr_type,
137 rr_class,
138 ttl,
139 rdata,
140 };
141 resources.push(r);
142 }
143 Ok((&original_data[*offset..], resources))
144}