Files
Nitrox/NitroxModel/Helper/NetHelper.cs
2025-07-06 00:23:46 +02:00

207 lines
6.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading.Tasks;
#if RELEASE
using System.Net.Http;
using System.Text.RegularExpressions;
#endif
namespace NitroxModel.Helper
{
public static class NetHelper
{
private static readonly string[] privateNetworks =
{
"10.0.0.0/8",
"127.0.0.0/8",
"172.16.0.0/12",
"192.0.0.0/24 ",
"192.168.0.0/16",
"198.18.0.0/15",
};
private static IPAddress wanIpCache;
private static IPAddress lanIpCache;
private static readonly object wanIpLock = new();
private static readonly object lanIpLock = new();
/// <summary>
/// Gets the network interfaces used for going onto the internet.
/// This is done by filtering for "Ethernet" and "Wi-Fi" network interfaces where "Ethernet" is returned earlier.
/// </summary>
/// <returns>Network interfaces used to go onto the internet.</returns>
public static IEnumerable<NetworkInterface> GetInternetInterfaces()
{
return NetworkInterface.GetAllNetworkInterfaces()
.Where(n => n.OperationalStatus is OperationalStatus.Up
&& n.NetworkInterfaceType is not (NetworkInterfaceType.Tunnel or NetworkInterfaceType.Loopback)
&& n.NetworkInterfaceType is (NetworkInterfaceType.Wireless80211 or NetworkInterfaceType.Ethernet))
.OrderBy(n => n.NetworkInterfaceType is NetworkInterfaceType.Ethernet ? 1 : 0)
.ThenBy(n => n.Name);
}
public static IPAddress GetLanIp()
{
lock (lanIpLock)
{
if (lanIpCache != null)
{
return lanIpCache;
}
}
foreach (NetworkInterface ni in GetInternetInterfaces())
{
foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
{
if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
{
lock (lanIpLock)
{
return lanIpCache = ip.Address;
}
}
}
}
return null;
}
public static async Task<IPAddress> GetWanIpAsync()
{
lock (wanIpLock)
{
if (wanIpCache != null)
{
return wanIpCache;
}
}
IPAddress ip = await NatHelper.GetExternalIpAsync();
#if RELEASE
if (ip == null || ip.IsPrivate())
{
Regex regex = new(@"(?:[0-2]??[0-9]{1,2}\.){3}[0-2]??[0-9]+");
string[] sites =
{
"https://ipv4.icanhazip.com/",
"https://checkip.amazonaws.com/",
"https://api.ipify.org/",
"https://api4.my-ip.io/ip",
"https://ifconfig.me/",
"https://showmyip.com/",
};
using HttpClient client = new();
foreach (string site in sites)
{
try
{
using HttpResponseMessage response = await client.GetAsync(site);
string content = await response.Content.ReadAsStringAsync();
ip = IPAddress.Parse(regex.Match(content).Value);
break;
}
catch
{
// ignore
}
}
}
#endif
lock (wanIpLock)
{
return wanIpCache = ip;
}
}
public static IPAddress GetHamachiIp()
{
foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
{
if (ni.Name != "Hamachi")
{
continue;
}
foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
{
if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
{
return ip.Address;
}
}
}
return null;
}
public static async Task<bool> HasInternetConnectivityAsync()
{
if (!NetworkInterface.GetIsNetworkAvailable())
{
return false;
}
using Ping ping = new();
PingReply reply = await ping.SendPingAsync(new IPAddress([8, 8, 8, 8]),2000);
return reply.Status == IPStatus.Success;
}
/// <summary>
/// Returns true if the given IP address is reserved for private networks.
/// </summary>
public static bool IsPrivate(this IPAddress address)
{
static bool IsInRange(IPAddress ipAddress, string mask)
{
string[] parts = mask.Split('/');
int ipNum = BitConverter.ToInt32(ipAddress.GetAddressBytes(), 0);
int cidrAddress = BitConverter.ToInt32(IPAddress.Parse(parts[0]).GetAddressBytes(), 0);
int cidrMask = IPAddress.HostToNetworkOrder(-1 << (32 - int.Parse(parts[1])));
return (ipNum & cidrMask) == (cidrAddress & cidrMask);
}
foreach (string privateSubnet in privateNetworks)
{
if (IsInRange(address, privateSubnet))
{
return true;
}
}
return false;
}
/// <summary>
/// Returns true if the IP address points to the executing machine.
/// </summary>
public static bool IsLocalhost(this IPAddress address)
{
if (address == null)
{
return false;
}
if (IPAddress.IsLoopback(address))
{
return true;
}
foreach (NetworkInterface ni in GetInternetInterfaces())
{
foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
{
if (address.Equals(ip.Address))
{
return true;
}
}
}
return false;
}
}
}