netbios_parser/
nbss_parser.rs

1use 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
19/// Parse a NetBIOS Name Service Header
20pub 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 (rem, d) = length_data(be_u16)(b)?;
65            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
74/// Parse a NetBIOS Name Service Packet (query or response)
75pub 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    // do not allocate with capacity (risk of DoS)
81    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}