use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use steamkit_protos::steam::{c_msg_ip_address, CMsgIpAddress};
use crate::base::generated::steam_language_internal::MsgClientLogon;
use crate::error::SteamError;
#[derive(Debug)]
pub struct NetHelpers;
impl NetHelpers {
pub fn get_local_ip(local_end_point: Option<SocketAddr>) -> Result<IpAddr, SteamError> {
match local_end_point {
Some(end_point) if !end_point.ip().is_unspecified() => Ok(end_point.ip()),
_ => Err(SteamError::Connection("Socket not connected".to_string())),
}
}
pub fn get_ip_address(ip_addr: u32) -> IpAddr {
IpAddr::V4(Ipv4Addr::from(ip_addr))
}
pub fn get_ip_address_as_uint(ip_addr: &IpAddr) -> Result<u32, SteamError> {
match ip_addr {
IpAddr::V4(address) => Ok(u32::from_be_bytes(address.octets())),
IpAddr::V6(_) => Err(SteamError::InvalidArgument(
"GetIPAddressAsUInt only works with IPv4 addresses.".to_string(),
)),
}
}
pub fn get_ip_address_from_msg(ip_addr: &CMsgIpAddress) -> Option<IpAddr> {
match &ip_addr.ip {
Some(c_msg_ip_address::Ip::V6(bytes)) => {
let octets: [u8; 16] = bytes.as_slice().try_into().ok()?;
Some(IpAddr::V6(Ipv6Addr::from(octets)))
}
Some(c_msg_ip_address::Ip::V4(value)) => {
Some(IpAddr::V4(Ipv4Addr::from(*value)))
}
None => None,
}
}
pub fn get_msg_ip_address(ip_addr: &IpAddr) -> CMsgIpAddress {
let ip = match ip_addr {
IpAddr::V4(address) => {
c_msg_ip_address::Ip::V4(u32::from_be_bytes(address.octets()))
}
IpAddr::V6(address) => c_msg_ip_address::Ip::V6(address.octets().to_vec()),
};
CMsgIpAddress { ip: Some(ip) }
}
pub fn obfuscate_private_ip(msg_ip_address: &mut CMsgIpAddress) {
match &mut msg_ip_address.ip {
Some(c_msg_ip_address::Ip::V6(bytes)) => {
const KEY: [u8; 4] = [0x0D, 0xF0, 0xAD, 0xBA];
for (index, byte) in bytes.iter_mut().enumerate() {
*byte ^= KEY[index % KEY.len()];
}
}
Some(c_msg_ip_address::Ip::V4(value)) => {
*value ^= MsgClientLogon::OBFUSCATION_MASK;
}
None => {}
}
}
pub fn try_parse_ip_end_point(string_value: &str) -> Option<SocketAddr> {
let end_point = string_value.parse::<SocketAddr>().ok()?;
if end_point.port() == 0 {
return None;
}
Some(end_point)
}
pub fn extract_endpoint_host(end_point: &SocketAddr) -> String {
end_point.ip().to_string()
}
pub fn extract_endpoint_port(end_point: &SocketAddr) -> u16 {
end_point.port()
}
}