netlink_packet_utils/
parsers.rs

1// SPDX-License-Identifier: MIT
2
3use std::{
4    mem::size_of,
5    net::{IpAddr, Ipv4Addr, Ipv6Addr},
6};
7
8use anyhow::Context;
9use byteorder::{BigEndian, ByteOrder, NativeEndian};
10
11use crate::DecodeError;
12
13pub fn parse_mac(payload: &[u8]) -> Result<[u8; 6], DecodeError> {
14    if payload.len() != 6 {
15        return Err(format!("invalid MAC address: {payload:?}").into());
16    }
17    let mut address: [u8; 6] = [0; 6];
18    for (i, byte) in payload.iter().enumerate() {
19        address[i] = *byte;
20    }
21    Ok(address)
22}
23
24pub fn parse_ipv6(payload: &[u8]) -> Result<[u8; 16], DecodeError> {
25    if payload.len() != 16 {
26        return Err(format!("invalid IPv6 address: {payload:?}").into());
27    }
28    let mut address: [u8; 16] = [0; 16];
29    for (i, byte) in payload.iter().enumerate() {
30        address[i] = *byte;
31    }
32    Ok(address)
33}
34
35pub fn parse_ip(payload: &[u8]) -> Result<IpAddr, DecodeError> {
36    match payload.len() {
37        4 => Ok(
38            Ipv4Addr::new(payload[0], payload[1], payload[2], payload[3])
39                .into(),
40        ),
41        16 => Ok(Ipv6Addr::from([
42            payload[0],
43            payload[1],
44            payload[2],
45            payload[3],
46            payload[4],
47            payload[5],
48            payload[6],
49            payload[7],
50            payload[8],
51            payload[9],
52            payload[10],
53            payload[11],
54            payload[12],
55            payload[13],
56            payload[14],
57            payload[15],
58        ])
59        .into()),
60        _ => Err(format!("invalid IPv6 address: {payload:?}").into()),
61    }
62}
63
64pub fn parse_string(payload: &[u8]) -> Result<String, DecodeError> {
65    if payload.is_empty() {
66        return Ok(String::new());
67    }
68    // iproute2 is a bit inconsistent with null-terminated strings.
69    let slice = if payload[payload.len() - 1] == 0 {
70        &payload[..payload.len() - 1]
71    } else {
72        &payload[..payload.len()]
73    };
74    let s = String::from_utf8(slice.to_vec()).context("invalid string")?;
75    Ok(s)
76}
77
78pub fn parse_u8(payload: &[u8]) -> Result<u8, DecodeError> {
79    if payload.len() != 1 {
80        return Err(format!("invalid u8: {payload:?}").into());
81    }
82    Ok(payload[0])
83}
84
85pub fn parse_u32(payload: &[u8]) -> Result<u32, DecodeError> {
86    if payload.len() != size_of::<u32>() {
87        return Err(format!("invalid u32: {payload:?}").into());
88    }
89    Ok(NativeEndian::read_u32(payload))
90}
91
92pub fn parse_u64(payload: &[u8]) -> Result<u64, DecodeError> {
93    if payload.len() != size_of::<u64>() {
94        return Err(format!("invalid u64: {payload:?}").into());
95    }
96    Ok(NativeEndian::read_u64(payload))
97}
98
99pub fn parse_u128(payload: &[u8]) -> Result<u128, DecodeError> {
100    if payload.len() != size_of::<u128>() {
101        return Err(format!("invalid u128: {payload:?}").into());
102    }
103    Ok(NativeEndian::read_u128(payload))
104}
105
106pub fn parse_u16(payload: &[u8]) -> Result<u16, DecodeError> {
107    if payload.len() != size_of::<u16>() {
108        return Err(format!("invalid u16: {payload:?}").into());
109    }
110    Ok(NativeEndian::read_u16(payload))
111}
112
113pub fn parse_i32(payload: &[u8]) -> Result<i32, DecodeError> {
114    if payload.len() != 4 {
115        return Err(format!("invalid u32: {payload:?}").into());
116    }
117    Ok(NativeEndian::read_i32(payload))
118}
119
120pub fn parse_u16_be(payload: &[u8]) -> Result<u16, DecodeError> {
121    if payload.len() != size_of::<u16>() {
122        return Err(format!("invalid u16: {payload:?}").into());
123    }
124    Ok(BigEndian::read_u16(payload))
125}
126
127pub fn parse_u32_be(payload: &[u8]) -> Result<u32, DecodeError> {
128    if payload.len() != size_of::<u32>() {
129        return Err(format!("invalid u32: {payload:?}").into());
130    }
131    Ok(BigEndian::read_u32(payload))
132}