dbs_utils/net/
mac.rs

1// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3//
4// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
5// Use of this source code is governed by a BSD-style license that can be
6// found in the THIRD-PARTY file.
7
8use std::fmt;
9use std::result::Result;
10
11use serde::de::{Deserialize, Deserializer, Error};
12use serde::ser::{Serialize, Serializer};
13
14/// Segments of MAC address separated by ":".
15pub const MAC_ADDR_LEN: usize = 6;
16
17#[derive(Debug)]
18pub enum MacError {
19    MacLengthError(usize),
20}
21
22/// MAC address for ethernet NIC.
23#[derive(Clone, Copy, Debug, Eq, PartialEq)]
24pub struct MacAddr {
25    bytes: [u8; MAC_ADDR_LEN],
26}
27
28impl MacAddr {
29    /// Parse a string into an MacAddr object.
30    /// The error contains the str that failed to be parsed, for nicer error message generation.
31    pub fn parse_str<S>(s: &S) -> Result<MacAddr, &str>
32    where
33        S: AsRef<str> + ?Sized,
34    {
35        let v: Vec<&str> = s.as_ref().split(':').collect();
36        let mut bytes = [0u8; MAC_ADDR_LEN];
37
38        if v.len() != MAC_ADDR_LEN {
39            return Err(s.as_ref());
40        }
41
42        for i in 0..MAC_ADDR_LEN {
43            if v[i].len() != 2 {
44                return Err(s.as_ref());
45            }
46            bytes[i] = u8::from_str_radix(v[i], 16).map_err(|_| s.as_ref())?;
47        }
48
49        Ok(MacAddr { bytes })
50    }
51
52    /// Create a MacAddr object from raw bytes unchecked.
53    ///
54    /// Does not check whether src.len() == MAC_ADDR_LEN.
55    #[inline]
56    pub fn from_bytes_unchecked(src: &[u8]) -> MacAddr {
57        let mut bytes = [0u8; MAC_ADDR_LEN];
58        let _ = &bytes[..].copy_from_slice(src);
59
60        MacAddr { bytes }
61    }
62
63    /// Create a MacAddr object from raw bytes.
64    #[inline]
65    pub fn from_bytes(src: &[u8]) -> Result<MacAddr, MacError> {
66        if src.len() != MAC_ADDR_LEN {
67            return Err(MacError::MacLengthError(src.len()));
68        }
69        Ok(MacAddr::from_bytes_unchecked(src))
70    }
71
72    /// Get raw bytes of the MacAddr object.
73    #[inline]
74    pub fn get_bytes(&self) -> &[u8] {
75        &self.bytes
76    }
77}
78
79impl fmt::Display for MacAddr {
80    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81        let b = &self.bytes;
82        write!(
83            f,
84            "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
85            b[0], b[1], b[2], b[3], b[4], b[5]
86        )
87    }
88}
89
90impl Serialize for MacAddr {
91    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
92    where
93        S: Serializer,
94    {
95        self.to_string().serialize(serializer)
96    }
97}
98
99impl<'de> Deserialize<'de> for MacAddr {
100    fn deserialize<D>(deserializer: D) -> Result<MacAddr, D::Error>
101    where
102        D: Deserializer<'de>,
103    {
104        let s = String::deserialize(deserializer)?;
105        MacAddr::parse_str(&s).map_err(|_| D::Error::custom("The provided MAC address is invalid."))
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112
113    #[test]
114    fn test_mac_addr() {
115        // too long
116        assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:aa:aa").is_err());
117
118        // invalid hex
119        assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:ax").is_err());
120
121        // single digit mac address component should be invalid
122        assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:b").is_err());
123
124        // components with more than two digits should also be invalid
125        assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:bbb").is_err());
126
127        let mac = MacAddr::parse_str("12:34:56:78:9a:BC").unwrap();
128
129        println!("parsed MAC address: {}", mac);
130
131        let bytes = mac.get_bytes();
132        assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]);
133    }
134
135    #[test]
136    fn test_from_bytes() {
137        let src1 = [0x01, 0x02, 0x03, 0x04, 0x05];
138        let src2 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06];
139        let src3 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
140
141        assert!(MacAddr::from_bytes(&src1[..]).is_err());
142
143        let x = MacAddr::from_bytes(&src2[..]).unwrap();
144        assert_eq!(x.to_string(), String::from("01:02:03:04:05:06"));
145
146        assert!(MacAddr::from_bytes(&src3[..]).is_err());
147    }
148
149    #[cfg(feature = "with-serde")]
150    #[test]
151    fn test_mac_addr_serialization_and_deserialization() {
152        let mac: MacAddr =
153            serde_json::from_str("\"12:34:56:78:9a:bc\"").expect("MacAddr deserialization failed.");
154
155        let bytes = mac.get_bytes();
156        assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]);
157
158        let s = serde_json::to_string(&mac).expect("MacAddr serialization failed.");
159        assert_eq!(s, "\"12:34:56:78:9a:bc\"");
160    }
161}