// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using Microsoft.PowerToys.Run.Plugin.System.Properties;
namespace Microsoft.PowerToys.Run.Plugin.System.Components
{
///
/// This class represents the informations for a network connection/interface
///
internal class NetworkConnectionProperties
{
///
/// Gets the name of the adapter
///
internal string Adapter { get; private set; }
///
/// Gets the physical address (MAC) of the adapter
///
internal string PhysicalAddress { get; private set; }
///
/// Gets a value indicating the interface type
///
internal NetworkInterfaceType Type { get; private set; }
///
/// Gets the speed of the adapter as unformatted value (Static information form the adapter device)
///
internal long Speed { get; private set; }
///
/// Gets a value indicating the operational state of the adapter
///
internal OperationalStatus State { get; private set; }
///
/// Gets the name of the network connection
///
internal string ConnectionName { get; private set; }
///
/// Gets a string with the suffix of the connection
///
internal string Suffix { get; private set; }
///
/// Gets the IPv4 address
///
internal string IPv4 { get; private set; }
///
/// Gets the IPv4 subnet mask
///
internal string IPv4Mask { get; private set; }
///
/// Gets the primarily used IPv6 address
///
internal string IPv6Primary { get; private set; }
///
/// Gets the global IPv6 address
///
internal string IPv6Global { get; private set; }
///
/// Gets the temporary IPv6 address
///
internal string IPv6Temporary { get; private set; }
///
/// Gets the link local IPv6 address
///
internal string IPv6LinkLocal { get; private set; }
///
/// Gets the site local IPv6 address
///
internal string IPv6SiteLocal { get; private set; }
///
/// Gets the unique local IPv6 address
///
internal string IPv6UniqueLocal { get; private set; }
///
/// Gets the list of gateway IPs as string
///
internal List Gateways { get; private set; } = new List();
///
/// Gets the list of DHCP server IPs as string
///
internal List DhcpServers { get; private set; } = new List();
///
/// Gets the list of DNS server IPs as string
///
internal List DnsServers { get; private set; } = new List();
///
/// Gets the list of WINS server IPs as string
///
internal List WinsServers { get; private set; } = new List();
///
/// Initializes a new instance of the class.
///
/// Network interface of the connection
internal NetworkConnectionProperties(NetworkInterface networkInterface)
{
// Setting adapter properties
Adapter = networkInterface.Description;
PhysicalAddress = networkInterface.GetPhysicalAddress().ToString();
Type = networkInterface.NetworkInterfaceType;
Speed = networkInterface.Speed;
State = networkInterface.OperationalStatus;
// Connection properties
ConnectionName = networkInterface.Name;
if (State == OperationalStatus.Up)
{
Suffix = networkInterface.GetIPProperties().DnsSuffix;
SetIpProperties(networkInterface.GetIPProperties());
}
}
///
/// Gets a formatted string with the adapter details
///
/// String with the details
internal string GetAdapterDetails()
{
return $"{Resources.Microsoft_plugin_sys_AdapterName}: {Adapter}" +
$"\n{Resources.Microsoft_plugin_sys_PhysicalAddress}: {PhysicalAddress}" +
$"\n{Resources.Microsoft_plugin_sys_Speed}: {GetFormattedSpeedValue(Speed)}" +
$"\n{Resources.Microsoft_plugin_sys_Type}: {GetAdapterTypeAsString(Type)}" +
$"\n{Resources.Microsoft_plugin_sys_State}: " + (State == OperationalStatus.Up ? Resources.Microsoft_plugin_sys_Connected : Resources.Microsoft_plugin_sys_Disconnected) +
$"\n{Resources.Microsoft_plugin_sys_ConnectionName}: {ConnectionName}";
}
///
/// Returns a formatted string with the connection details
///
/// String with the details
internal string GetConnectionDetails()
{
return $"{Resources.Microsoft_plugin_sys_ConnectionName}: {ConnectionName}" +
$"\n{Resources.Microsoft_plugin_sys_State}: " + (State == OperationalStatus.Up ? Resources.Microsoft_plugin_sys_Connected : Resources.Microsoft_plugin_sys_Disconnected) +
$"\n{Resources.Microsoft_plugin_sys_Type}: {GetAdapterTypeAsString(Type)}" +
$"\n{Resources.Microsoft_plugin_sys_Suffix}: {Suffix}" +
CreateIpInfoForDetailsText($"{Resources.Microsoft_plugin_sys_Ip4Address}: ", IPv4) +
CreateIpInfoForDetailsText($"{Resources.Microsoft_plugin_sys_Ip4SubnetMask}: ", IPv4Mask) +
CreateIpInfoForDetailsText($"{Resources.Microsoft_plugin_sys_Ip6Address}:\n\t", IPv6Global) +
CreateIpInfoForDetailsText($"{Resources.Microsoft_plugin_sys_Ip6Temp}:\n\t", IPv6Temporary) +
CreateIpInfoForDetailsText($"{Resources.Microsoft_plugin_sys_Ip6Link}:\n\t", IPv6LinkLocal) +
CreateIpInfoForDetailsText($"{Resources.Microsoft_plugin_sys_Ip6Site}:\n\t", IPv6SiteLocal) +
CreateIpInfoForDetailsText($"{Resources.Microsoft_plugin_sys_Ip6Unique}:\n\t", IPv6UniqueLocal) +
CreateIpInfoForDetailsText($"{Resources.Microsoft_plugin_sys_Gateways}:\n\t", Gateways) +
CreateIpInfoForDetailsText($"{Resources.Microsoft_plugin_sys_Dhcp}:\n\t", DhcpServers) +
CreateIpInfoForDetailsText($"{Resources.Microsoft_plugin_sys_Dns}:\n\t", DnsServers) +
CreateIpInfoForDetailsText($"{Resources.Microsoft_plugin_sys_Wins}:\n\t", WinsServers) +
$"\n\n{Resources.Microsoft_plugin_sys_AdapterName}: {Adapter}" +
$"\n{Resources.Microsoft_plugin_sys_PhysicalAddress}: {PhysicalAddress}" +
$"\n{Resources.Microsoft_plugin_sys_Speed}: {GetFormattedSpeedValue(Speed)}";
}
///
/// Set the ip address properties of the instance.
///
/// Element of the type .
private void SetIpProperties(IPInterfaceProperties properties)
{
var ipList = properties.UnicastAddresses;
foreach (var ip in ipList)
{
if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
{
IPv4 = ip.Address.ToString();
IPv4Mask = ip.IPv4Mask.ToString();
}
else if (ip.Address.AddressFamily == AddressFamily.InterNetworkV6)
{
if (string.IsNullOrEmpty(IPv6Primary))
{
IPv6Primary = ip.Address.ToString();
}
if (ip.Address.IsIPv6LinkLocal)
{
IPv6LinkLocal = ip.Address.ToString();
}
else if (ip.Address.IsIPv6SiteLocal)
{
IPv6SiteLocal = ip.Address.ToString();
}
else if (ip.Address.IsIPv6UniqueLocal)
{
IPv6UniqueLocal = ip.Address.ToString();
}
else if (ip.SuffixOrigin == SuffixOrigin.Random)
{
IPv6Temporary = ip.Address.ToString();
}
else
{
IPv6Global = ip.Address.ToString();
}
}
}
foreach (var ip in properties.GatewayAddresses)
{
Gateways.Add(ip.Address.ToString());
}
foreach (var ip in properties.DhcpServerAddresses)
{
DhcpServers.Add(ip.ToString());
}
foreach (var ip in properties.DnsAddresses)
{
DnsServers.Add(ip.ToString());
}
foreach (var ip in properties.WinsServersAddresses)
{
WinsServers.Add(ip.ToString());
}
}
///
/// Gets the interface type as string
///
/// The type to convert
/// A string indicating the interface type
private string GetAdapterTypeAsString(NetworkInterfaceType type)
{
switch (type)
{
case NetworkInterfaceType.Wman:
case NetworkInterfaceType.Wwanpp:
case NetworkInterfaceType.Wwanpp2:
return Resources.Microsoft_plugin_sys_MobileBroadband;
case NetworkInterfaceType.Wireless80211:
return Resources.Microsoft_plugin_sys_WirelessLan;
case NetworkInterfaceType.Loopback:
return Resources.Microsoft_plugin_sys_Loopback;
case NetworkInterfaceType.Tunnel:
return Resources.Microsoft_plugin_sys_TunnelConnection;
case NetworkInterfaceType.Unknown:
return Resources.Microsoft_plugin_sys_Unknown;
default:
return Resources.Microsoft_plugin_sys_Cable;
}
}
///
/// Gets the speed as formatted text value
///
/// The adapter speed as .
/// A formatted string like `100 MB/s`
private static string GetFormattedSpeedValue(long speed)
{
return (speed >= 1000000000) ? string.Format(CultureInfo.InvariantCulture, Resources.Microsoft_plugin_sys_Gbps, speed / 1000000000) : string.Format(CultureInfo.InvariantCulture, Resources.Microsoft_plugin_sys_Mbps, speed / 1000000);
}
///
/// Returns IP info or an empty string
///
/// Descriptive header for the information.
/// IP value as or .
/// Formatted string or an empty string.
/// If the parameter is not of the type or .
private static string CreateIpInfoForDetailsText(string title, dynamic property)
{
if (property is string)
{
return $"\n{title}{property}";
}
else if (property is List list)
{
return list.Count == 0 ? string.Empty : $"\n{title}{string.Join("\n\t", property)}";
}
else if (property is null)
{
return string.Empty;
}
else
{
throw new ArgumentException($"'{property}' is not of type 'string' or 'List'.", nameof(property));
}
}
}
}