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 unsafe { 86 // Man page says this function will not be interrupted by a signal 87 // for requests less than 256 bytes 88 if libc::getrandom( 89 random_bytes.as_mut_ptr() as *mut _ as *mut libc::c_void, 90 MAC_ADDR_LEN, 91 0, 92 ) < 0 93 { 94 error!( 95 "Error populating MAC address with random data: {}", 96 std::io::Error::last_os_error() 97 ) 98 } 99 }; 100 101 // Set the first byte to make the OUI a locally administered OUI 102 random_bytes[0] = 0x2e; 103 104 MacAddr { 105 bytes: random_bytes, 106 } 107 } 108 } 109 110 impl fmt::Display for MacAddr { 111 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 112 let b = &self.bytes; 113 write!( 114 f, 115 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", 116 b[0], b[1], b[2], b[3], b[4], b[5] 117 ) 118 } 119 } 120 121 impl Serialize for MacAddr { 122 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 123 where 124 S: Serializer, 125 { 126 self.to_string().serialize(serializer) 127 } 128 } 129 130 impl<'de> Deserialize<'de> for MacAddr { 131 fn deserialize<D>(deserializer: D) -> Result<MacAddr, D::Error> 132 where 133 D: Deserializer<'de>, 134 { 135 let s = String::deserialize(deserializer)?; 136 MacAddr::parse_str(&s) 137 .map_err(|e| D::Error::custom(format!("The provided MAC address is invalid: {}", e))) 138 } 139 } 140 141 pub enum MacAddrParseError { 142 InvalidValue(String), 143 } 144 145 impl FromStr for MacAddr { 146 type Err = MacAddrParseError; 147 148 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { 149 MacAddr::parse_str(s).map_err(|_| MacAddrParseError::InvalidValue(s.to_owned())) 150 } 151 } 152 153 #[cfg(test)] 154 mod tests { 155 use super::*; 156 157 #[test] 158 fn test_mac_addr() { 159 // too long 160 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:aa:aa").is_err()); 161 162 // invalid hex 163 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:ax").is_err()); 164 165 // single digit mac address component should be invalid 166 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:b").is_err()); 167 168 // components with more than two digits should also be invalid 169 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:bbb").is_err()); 170 171 let mac = MacAddr::parse_str("12:34:56:78:9a:BC").unwrap(); 172 173 println!("parsed MAC address: {}", mac.to_string()); 174 175 let bytes = mac.get_bytes(); 176 assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]); 177 } 178 179 #[test] 180 fn test_from_bytes() { 181 let src1 = [0x01, 0x02, 0x03, 0x04, 0x05]; 182 let src2 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]; 183 let src3 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]; 184 185 assert!(MacAddr::from_bytes(&src1[..]).is_err()); 186 187 let x = MacAddr::from_bytes(&src2[..]).unwrap(); 188 assert_eq!(x.to_string(), String::from("01:02:03:04:05:06")); 189 190 assert!(MacAddr::from_bytes(&src3[..]).is_err()); 191 } 192 193 #[test] 194 fn test_mac_addr_serialization_and_deserialization() { 195 let mac: MacAddr = 196 serde_json::from_str("\"12:34:56:78:9a:bc\"").expect("MacAddr deserialization failed."); 197 198 let bytes = mac.get_bytes(); 199 assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]); 200 201 let s = serde_json::to_string(&mac).expect("MacAddr serialization failed."); 202 assert_eq!(s, "\"12:34:56:78:9a:bc\""); 203 } 204 } 205