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
use std::net::Ipv4Addr; use std::num::Wrapping; use common::bytes::BytesAbleNum; const USERNAME_MAX_LEN: usize = 30; const MAC_ADDRESS_LEN: usize = 18; #[derive(Debug)] pub enum MACOpenErr { UsernameTooLong(String), MACAddressError(String), } #[derive(Debug)] pub struct MACOpenPacket { username: String, ipaddress: Ipv4Addr, mac_address: String, isp: ISPCode, } #[derive(Debug)] pub enum Configuration { GUET, GXNU, } #[derive(Debug, Clone, Copy)] pub enum ISPCode { CChinaUnicom = 1 << 8, CChinaTelecom = 2 << 8, CChinaMobile = 3 << 8, } impl Configuration { pub fn hash_key(&self) -> u32 { match *self { _ => 0x4E67_C6A7, } } } impl MACOpenPacket { pub fn new(username: &str, ipaddress: Ipv4Addr, mac_address: &str, isp: ISPCode) -> Self { MACOpenPacket { username: username.to_string(), ipaddress, mac_address: mac_address.to_string(), isp, } } pub fn as_bytes(&self, hash_key: u32) -> Result<Vec<u8>, MACOpenErr> { let mut macopen_packet = Vec::with_capacity(60); { self.validate()?; let mut username_bytes = [0; USERNAME_MAX_LEN]; let mut mac_address_bytes = [0; MAC_ADDRESS_LEN]; username_bytes[..self.username.len()].clone_from_slice(self.username.as_bytes()); mac_address_bytes[..self.mac_address.len()] .clone_from_slice(self.mac_address.as_bytes()); macopen_packet.extend_from_slice(&username_bytes); macopen_packet.extend_from_slice(&self.ipaddress.octets()); macopen_packet.extend_from_slice(&mac_address_bytes); macopen_packet.extend((self.isp as u32).as_bytes_be()); let hash_bytes = Self::hash_bytes(&macopen_packet, hash_key); macopen_packet.extend_from_slice(&hash_bytes); } Ok(macopen_packet) } fn validate(&self) -> Result<(), MACOpenErr> { if self.username.len() > USERNAME_MAX_LEN - 1 { return Err(MACOpenErr::UsernameTooLong(self.username.clone())); } if self.mac_address.len() != MAC_ADDRESS_LEN - 1 { return Err(MACOpenErr::MACAddressError(self.mac_address.clone())); } Ok(()) } fn hash_bytes(bytes: &[u8], hash_key: u32) -> [u8; 4] { let mut hash = Wrapping(hash_key as i32); for c in bytes.iter() { hash ^= (hash << 5) + (hash >> 2) + Wrapping(i32::from(*c)); } hash &= Wrapping(0x7fff_ffff); let mut hash_bytes = [0; 4]; (hash.0 as u32).write_bytes_le(&mut hash_bytes); hash_bytes } } #[test] fn test_mac_opener_hash_bytes() { let bytes1 = [1, 2, 3, 4, 5, 6, 7, 0]; let hash_bytes1 = MACOpenPacket::hash_bytes(&bytes1, Configuration::GUET.hash_key()); let bytes2 = [97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 16, 1, 1, 52, 48, 58, 54, 49, 58, 56, 54, 58, 56, 55, 58, 57, 70, 58, 70, 49, 0, 0, 0, 1, 0]; let hash_bytes2 = MACOpenPacket::hash_bytes(&bytes2, Configuration::GUET.hash_key()); assert_eq!(hash_bytes1, [0x9c, 0x89, 0xf8, 0x3d]); assert_eq!(hash_bytes2, [255, 189, 40, 90]); }