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 8 use std::fmt; 9 use std::io; 10 use std::result::Result; 11 use std::str::FromStr; 12 13 use serde::de::{Deserialize, Deserializer, Error}; 14 use serde::ser::{Serialize, Serializer}; 15 16 pub const MAC_ADDR_LEN: usize = 6; 17 18 #[derive(Clone, Copy, Debug, PartialEq)] 19 pub struct MacAddr { 20 bytes: [u8; MAC_ADDR_LEN], 21 } 22 23 impl MacAddr { 24 pub fn parse_str<S>(s: &S) -> Result<MacAddr, io::Error> 25 where 26 S: AsRef<str> + ?Sized, 27 { 28 let v: Vec<&str> = s.as_ref().split(':').collect(); 29 let mut bytes = [0u8; MAC_ADDR_LEN]; 30 let common_err = Err(io::Error::new( 31 io::ErrorKind::Other, 32 format!("parsing of {} into a MAC address failed", s.as_ref()), 33 )); 34 35 if v.len() != MAC_ADDR_LEN { 36 return common_err; 37 } 38 39 for i in 0..MAC_ADDR_LEN { 40 if v[i].len() != 2 { 41 return common_err; 42 } 43 bytes[i] = u8::from_str_radix(v[i], 16).map_err(|e| { 44 io::Error::new( 45 io::ErrorKind::Other, 46 format!("parsing of {} into a MAC address failed: {}", s.as_ref(), e), 47 ) 48 })?; 49 } 50 51 Ok(MacAddr { bytes }) 52 } 53 54 // Does not check whether src.len() == MAC_ADDR_LEN. 55 #[inline] 56 pub fn from_bytes_unchecked(src: &[u8]) -> MacAddr { 57 // TODO: using something like std::mem::uninitialized could avoid the extra initialization, 58 // if this ever becomes a performance bottleneck. 59 let mut bytes = [0u8; MAC_ADDR_LEN]; 60 bytes[..].copy_from_slice(src); 61 62 MacAddr { bytes } 63 } 64 65 // An error can only occur if the slice length is different from MAC_ADDR_LEN. 66 #[inline] 67 pub fn from_bytes(src: &[u8]) -> Result<MacAddr, io::Error> { 68 if src.len() != MAC_ADDR_LEN { 69 return Err(io::Error::new( 70 io::ErrorKind::Other, 71 format!("invalid length of slice: {} vs {}", src.len(), MAC_ADDR_LEN), 72 )); 73 } 74 Ok(MacAddr::from_bytes_unchecked(src)) 75 } 76 77 #[inline] 78 pub fn get_bytes(&self) -> &[u8] { 79 &self.bytes 80 } 81 82 pub fn local_random() -> MacAddr { 83 // Generate a fully random MAC 84 let mut random_bytes = [0u8; MAC_ADDR_LEN]; 85 if let Err(e) = getrandom::getrandom(&mut random_bytes) { 86 error!( 87 "Error populating MAC address with random data: {}", 88 e.to_string() 89 ); 90 } 91 92 // Set the first byte to make the OUI a locally administered OUI 93 random_bytes[0] = 0x2e; 94 95 MacAddr { 96 bytes: random_bytes, 97 } 98 } 99 } 100 101 impl fmt::Display for MacAddr { 102 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 103 let b = &self.bytes; 104 write!( 105 f, 106 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", 107 b[0], b[1], b[2], b[3], b[4], b[5] 108 ) 109 } 110 } 111 112 impl Serialize for MacAddr { 113 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 114 where 115 S: Serializer, 116 { 117 self.to_string().serialize(serializer) 118 } 119 } 120 121 impl<'de> Deserialize<'de> for MacAddr { 122 fn deserialize<D>(deserializer: D) -> Result<MacAddr, D::Error> 123 where 124 D: Deserializer<'de>, 125 { 126 let s = String::deserialize(deserializer)?; 127 MacAddr::parse_str(&s) 128 .map_err(|e| D::Error::custom(format!("The provided MAC address is invalid: {}", e))) 129 } 130 } 131 132 pub enum MacAddrParseError { 133 InvalidValue(String), 134 } 135 136 impl FromStr for MacAddr { 137 type Err = MacAddrParseError; 138 139 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { 140 MacAddr::parse_str(s).map_err(|_| MacAddrParseError::InvalidValue(s.to_owned())) 141 } 142 } 143 144 #[cfg(test)] 145 mod tests { 146 use super::*; 147 148 #[test] 149 fn test_mac_addr() { 150 // too long 151 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:aa:aa").is_err()); 152 153 // invalid hex 154 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:ax").is_err()); 155 156 // single digit mac address component should be invalid 157 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:b").is_err()); 158 159 // components with more than two digits should also be invalid 160 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:bbb").is_err()); 161 162 let mac = MacAddr::parse_str("12:34:56:78:9a:BC").unwrap(); 163 164 println!("parsed MAC address: {}", mac); 165 166 let bytes = mac.get_bytes(); 167 assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]); 168 } 169 170 #[test] 171 fn test_from_bytes() { 172 let src1 = [0x01, 0x02, 0x03, 0x04, 0x05]; 173 let src2 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]; 174 let src3 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]; 175 176 assert!(MacAddr::from_bytes(&src1[..]).is_err()); 177 178 let x = MacAddr::from_bytes(&src2[..]).unwrap(); 179 assert_eq!(x.to_string(), String::from("01:02:03:04:05:06")); 180 181 assert!(MacAddr::from_bytes(&src3[..]).is_err()); 182 } 183 184 #[test] 185 fn test_mac_addr_serialization_and_deserialization() { 186 let mac: MacAddr = 187 serde_json::from_str("\"12:34:56:78:9a:bc\"").expect("MacAddr deserialization failed."); 188 189 let bytes = mac.get_bytes(); 190 assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]); 191 192 let s = serde_json::to_string(&mac).expect("MacAddr serialization failed."); 193 assert_eq!(s, "\"12:34:56:78:9a:bc\""); 194 } 195 } 196