steamkit/util/
net_helpers.rs1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
4
5use steamkit_protos::steam::{c_msg_ip_address, CMsgIpAddress};
6
7use crate::base::generated::steam_language_internal::MsgClientLogon;
8use crate::error::SteamError;
9
10#[derive(Debug)]
12pub struct NetHelpers;
13
14impl NetHelpers {
15 pub fn get_local_ip(local_end_point: Option<SocketAddr>) -> Result<IpAddr, SteamError> {
18 match local_end_point {
19 Some(end_point) if !end_point.ip().is_unspecified() => Ok(end_point.ip()),
20 _ => Err(SteamError::Connection("Socket not connected".to_string())),
21 }
22 }
23
24 pub fn get_ip_address(ip_addr: u32) -> IpAddr {
27 IpAddr::V4(Ipv4Addr::from(ip_addr))
28 }
29
30 pub fn get_ip_address_as_uint(ip_addr: &IpAddr) -> Result<u32, SteamError> {
33 match ip_addr {
34 IpAddr::V4(address) => Ok(u32::from_be_bytes(address.octets())),
35 IpAddr::V6(_) => Err(SteamError::InvalidArgument(
36 "GetIPAddressAsUInt only works with IPv4 addresses.".to_string(),
37 )),
38 }
39 }
40
41 pub fn get_ip_address_from_msg(ip_addr: &CMsgIpAddress) -> Option<IpAddr> {
44 match &ip_addr.ip {
45 Some(c_msg_ip_address::Ip::V6(bytes)) => {
46 let octets: [u8; 16] = bytes.as_slice().try_into().ok()?;
47 Some(IpAddr::V6(Ipv6Addr::from(octets)))
48 }
49 Some(c_msg_ip_address::Ip::V4(value)) => {
50 Some(IpAddr::V4(Ipv4Addr::from(*value)))
51 }
52 None => None,
53 }
54 }
55
56 pub fn get_msg_ip_address(ip_addr: &IpAddr) -> CMsgIpAddress {
58 let ip = match ip_addr {
59 IpAddr::V4(address) => {
60 c_msg_ip_address::Ip::V4(u32::from_be_bytes(address.octets()))
61 }
62 IpAddr::V6(address) => c_msg_ip_address::Ip::V6(address.octets().to_vec()),
63 };
64
65 CMsgIpAddress { ip: Some(ip) }
66 }
67
68 pub fn obfuscate_private_ip(msg_ip_address: &mut CMsgIpAddress) {
71 match &mut msg_ip_address.ip {
72 Some(c_msg_ip_address::Ip::V6(bytes)) => {
73 const KEY: [u8; 4] = [0x0D, 0xF0, 0xAD, 0xBA];
74
75 for (index, byte) in bytes.iter_mut().enumerate() {
76 *byte ^= KEY[index % KEY.len()];
77 }
78 }
79 Some(c_msg_ip_address::Ip::V4(value)) => {
80 *value ^= MsgClientLogon::OBFUSCATION_MASK;
81 }
82 None => {}
83 }
84 }
85
86 pub fn try_parse_ip_end_point(string_value: &str) -> Option<SocketAddr> {
88 let end_point = string_value.parse::<SocketAddr>().ok()?;
89
90 if end_point.port() == 0 {
91 return None;
92 }
93
94 Some(end_point)
95 }
96
97 pub fn extract_endpoint_host(end_point: &SocketAddr) -> String {
99 end_point.ip().to_string()
100 }
101
102 pub fn extract_endpoint_port(end_point: &SocketAddr) -> u16 {
104 end_point.port()
105 }
106}