Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better LocalIpAddress resolver #22

Merged
merged 5 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 57 additions & 48 deletions src/networking/networking/Implementation/LocalIpAddressProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,21 @@ internal set
/// </summary>
/// <param name="logger">The <see cref="ILogger"/></param>
/// <exception cref="ArgumentNullException"><paramref name="logger"/> cannot be null.</exception>
public LocalIpAddressProvider(ILogger logger)
public LocalIpAddressProvider(ILogger logger)
: this(new DnsWrapper(), logger)
{
}

internal LocalIpAddressProvider(IDns dns, ILogger logger)
/// <summary>
/// Construct a new instance of <see cref="LocalIpAddressProvider"/>
/// </summary>
/// <param name="dns">The <see cref="IDns"/></param>
/// <param name="logger">The <see cref="ILogger"/></param>
/// <exception cref="ArgumentNullException">
/// - <paramref name="dns"/> cannot be null.
/// - <paramref name="logger"/> cannot be null.
/// </exception>
public LocalIpAddressProvider(IDns dns, ILogger logger)
{
_Dns = dns ?? throw new ArgumentNullException(nameof(dns));
_Logger = logger ?? throw new ArgumentNullException(nameof(logger));
Expand All @@ -108,71 +117,71 @@ public IList<IPAddress> GetIpAddressesV4()
=> GetIpAddresses(AddressFamily.InterNetwork).ToList();

/// <inheritdoc cref="ILocalIpAddressProvider.GetIpAddressesV6"/>
public IList<IPAddress> GetIpAddressesV6()
public IList<IPAddress> GetIpAddressesV6()
=> GetIpAddresses(AddressFamily.InterNetworkV6).ToList();

internal void RefreshIpAddresses()
{
RefreshIpAddresses(AddressFamily.InterNetwork);
RefreshIpAddresses(AddressFamily.InterNetworkV6);
}

internal virtual void RefreshIpAddresses(AddressFamily addressFamily)
private IEnumerable<IPAddress> GetIpAddresses(AddressFamily addressFamily)
{
if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6)
{
_Logger.Error("Unsupported address family: {0}", addressFamily);
return;
}

var addresses = GetIpAddresses(addressFamily).ToList();
if (!addresses.Any())
{
_Logger.Error("No public {0} address found for server, while trying to refresh IP address in {1}!", addressFamily, nameof(RefreshIpAddresses));
return;
return Enumerable.Empty<IPAddress>();
}

if ((addressFamily == AddressFamily.InterNetwork && addresses.Contains(AddressV4)) ||
(addressFamily == AddressFamily.InterNetworkV6 && addresses.Contains(AddressV6)))
return;

var newIpAddress = addresses.First();

IPAddress oldIpAddress;
if (addressFamily == AddressFamily.InterNetwork)
{
oldIpAddress = AddressV4;

AddressV4 = newIpAddress;
}
else
{
oldIpAddress = AddressV6;
if (GetAddressesByInterface(NetworkInterfaceType.Wireless80211, addressFamily, out var ipAddresses) ||
GetAddressesByInterface(NetworkInterfaceType.Ethernet, addressFamily, out ipAddresses) ||
GetAddressesByInterface(NetworkInterfaceType.Loopback, addressFamily, out ipAddresses))
return ipAddresses;

AddressV6 = newIpAddress;
}
_Logger.Error("No public {0} address found for server on the following interfaces: {1}, {2}, {3}!", addressFamily, NetworkInterfaceType.Wireless80211, NetworkInterfaceType.Ethernet, NetworkInterfaceType.Loopback);

_Logger.Information("{0} IP address changed from {1} to {2}.", addressFamily, oldIpAddress, newIpAddress);
return Enumerable.Empty<IPAddress>();
}

internal virtual IEnumerable<IPAddress> GetIpAddresses(AddressFamily addressFamily)
private static bool GetAddressesByInterface(NetworkInterfaceType interfaceType, AddressFamily addressFamily, out IEnumerable<IPAddress> ipAddresses)
=> (ipAddresses = (from item in NetworkInterface.GetAllNetworkInterfaces()
where item.NetworkInterfaceType == interfaceType &&
item.OperationalStatus == OperationalStatus.Up
select item.GetIPProperties().UnicastAddresses
into unicastAddresses
select unicastAddresses.FirstOrDefault()?.Address
into address
where address != null &&
address.AddressFamily == addressFamily
select address))?.Any() ?? false;

private void RefreshIpAddresses(AddressFamily addressFamily)
{
IPHostEntry hostEntry;
try
if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6)
{
hostEntry = _Dns.GetHostEntry(_Dns.GetHostName());
_Logger.Error("Unsupported address family: {0}", addressFamily);

return;
}
catch (Exception ex)

// Try Wi-Fi first, then Ethernet and finally Loopback
if (GetAddressesByInterface(NetworkInterfaceType.Wireless80211, addressFamily, out var newIpAddresses) ||
GetAddressesByInterface(NetworkInterfaceType.Ethernet, addressFamily, out newIpAddresses) ||
GetAddressesByInterface(NetworkInterfaceType.Loopback, addressFamily, out newIpAddresses))
{
_Logger.Error("Exception encountered while acquiring host information from DNS: {0}", ex);
var newIpAddress = newIpAddresses.First();
var oldIpAddress = addressFamily == AddressFamily.InterNetwork ? AddressV4 : AddressV6;

return Enumerable.Empty<IPAddress>();
if (addressFamily == AddressFamily.InterNetwork)
AddressV4 = newIpAddress;
else
AddressV6 = newIpAddress;

_Logger.Information("{0} IP address changed from {1} to {2}.", addressFamily, oldIpAddress, newIpAddress);
}
if (hostEntry == null)
return Enumerable.Empty<IPAddress>();
else
_Logger.Error("No public {0} address found for server on the following interfaces: {1}, {2}, {3}!", addressFamily, NetworkInterfaceType.Wireless80211, NetworkInterfaceType.Ethernet, NetworkInterfaceType.Loopback);
}

return (from address in hostEntry.AddressList
where address.AddressFamily == addressFamily
select address).ToList();
internal void RefreshIpAddresses()
{
RefreshIpAddresses(AddressFamily.InterNetwork);
RefreshIpAddresses(AddressFamily.InterNetworkV6);
}
}
2 changes: 1 addition & 1 deletion src/networking/networking/Networking.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<Description>Library used for IP address parsing and more!</Description>

<Version>1.0.4</Version>
<Version>1.0.5</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
Loading