1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use crate::error::*;
use crate::nbss_types::*;
use crate::nom;
use dns_parser::Name;
use nom::error::ParseError;
use nom::multi::count;
use nom::number::streaming::{be_u16, be_u32, be_u8};
use nom::{bytes::streaming::take, IResult};
use std::net::Ipv4Addr;

pub(crate) fn be_u48<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], u64, E> {
    let (i, hb) = be_u32(i)?;
    let (i, lb) = be_u16(i)?;
    let n = ((hb as u64) << 16) | (lb as u64);
    Ok((i, n))
}

/// Parse a NetBIOS Name Service Header
pub fn parse_nbss_header(i: &[u8]) -> Result<NbssHeader> {
    let (rem, bytes) = take(NbssHeader::size())(i)?;
    let name_trn_id = ((bytes[0] as u16) << 8) + (bytes[1]) as u16;
    let fields_16_32 = ((bytes[2] as u16) << 8) + (bytes[3] as u16);
    let qdcount = ((bytes[4] as u16) << 8) + (bytes[5] as u16);
    let ancount = ((bytes[6] as u16) << 8) + (bytes[7] as u16);
    let nscount = ((bytes[8] as u16) << 8) + (bytes[9] as u16);
    let arcount = ((bytes[10] as u16) << 8) + (bytes[11] as u16);
    Ok((
        rem,
        NbssHeader {
            name_trn_id,
            fields_16_32,
            qdcount,
            ancount,
            nscount,
            arcount,
        },
    ))
}

fn parse_node_name(i: &[u8]) -> Result<NodeName> {
    let (rem, b) = take(16usize)(i)?;
    let s = std::string::String::from_utf8_lossy(b);
    let name = NetbiosName::from_bytes(s.as_bytes())?;
    let (rem, name_flags) = be_u16(rem)?;
    Ok((rem, NodeName { name, name_flags }))
}

fn parse_rdata(b: &[u8], rtype: RType) -> Result<RData> {
    match rtype {
        RType::NB => {
            let (rem, nb_flags) = be_u16(b)?;
            let (rem, addr) = take(4usize)(rem)?;
            let nb_address = Ipv4Addr::new(addr[0], addr[1], addr[2], addr[3]);
            Ok((
                rem,
                RData::NB {
                    nb_flags,
                    nb_address,
                },
            ))
        }
        RType::NBSTAT => {
            // let (rem, d) = length_data(be_u16)(b)?;
            let (d, num_names) = be_u8(b)?;
            let (rem, names) = count(parse_node_name, num_names as usize)(d)?;
            let (rem, stats) = NodeStatistics::parse(rem)?;
            Ok((rem, RData::NBStat { names, stats }))
        }
        _ => Ok((&[], RData::Unknown(b))),
    }
}

/// Parse a NetBIOS Name Service Packet (query or response)
pub fn parse_nbss_packet(i: &[u8]) -> Result<NbssPacket> {
    let original_data = i;
    let (_, header) = parse_nbss_header(i)?;
    let mut offset = NbssHeader::size();
    let num_questions = header.qdcount as usize;
    // do not allocate with capacity (risk of DoS)
    let mut questions = Vec::new();
    for _ in 0..num_questions {
        let name = Name::scan(&original_data[offset..], original_data)
            .map_err(|_| NetbiosError::InvalidQuestion)?;
        offset += name.byte_len();
        let qname = EncodedName(name.to_string());
        let (rem, qtype) = QType::parse(&original_data[offset..])?;
        let (_, qclass) = RClass::parse(rem)?;
        offset += 4;
        let q = NetbiosQuestion {
            qname,
            qtype,
            qclass,
        };
        questions.push(q);
    }
    let (_, rr_answer) =
        parse_resource_records(header.ancount as usize, original_data, &mut offset)?;
    let (_, rr_authority) =
        parse_resource_records(header.nscount as usize, original_data, &mut offset)?;
    let (_, rr_additional) =
        parse_resource_records(header.arcount as usize, original_data, &mut offset)?;
    Ok((
        &original_data[offset..],
        NbssPacket {
            header,
            questions,
            rr_answer,
            rr_authority,
            rr_additional,
        },
    ))
}

fn parse_resource_records<'a>(
    num_records: usize,
    original_data: &'a [u8],
    offset: &'_ mut usize,
) -> Result<'a, Vec<NetbiosResource<'a>>> {
    let mut resources = Vec::new();
    for _ in 0..num_records {
        let name = Name::scan(&original_data[*offset..], original_data)
            .map_err(|_| NetbiosError::InvalidAnswer)?;
        *offset += name.byte_len();
        let rr_name = EncodedName(name.to_string());
        let data = &original_data[*offset..];
        let (rem, rr_type) = RType::parse(data)?;
        let (rem, rr_class) = RClass::parse(rem)?;
        let (rem, ttl) = be_u32(rem)?;
        let (rem, rd_length) = be_u16(rem)?;
        let (_, b) = take(rd_length as usize)(rem)?;
        let (_, rdata) = parse_rdata(b, rr_type)?;
        *offset += (10 + rd_length) as usize;
        let r = NetbiosResource {
            rr_name,
            rr_type,
            rr_class,
            ttl,
            rdata,
        };
        resources.push(r);
    }
    Ok((&original_data[*offset..], resources))
}