2022-03-21 13:37:51 +01:00
// 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 ;
2022-04-04 13:47:58 +02:00
using System.Diagnostics ;
2022-03-21 13:37:51 +01:00
using System.Globalization ;
2022-04-04 13:47:58 +02:00
using System.Linq ;
using System.Net ;
2022-03-21 13:37:51 +01:00
using System.Net.NetworkInformation ;
using System.Net.Sockets ;
2023-12-28 13:37:13 +03:00
using System.Text ;
2024-09-16 16:09:43 -04:00
2022-03-21 13:37:51 +01:00
using Microsoft.PowerToys.Run.Plugin.System.Properties ;
namespace Microsoft.PowerToys.Run.Plugin.System.Components
{
/// <summary>
2023-10-04 11:07:40 +01:00
/// This class represents the information for a network connection/interface
2022-03-21 13:37:51 +01:00
/// </summary>
2023-03-16 15:51:31 +01:00
internal sealed class NetworkConnectionProperties
2022-03-21 13:37:51 +01:00
{
/// <summary>
/// Gets the name of the adapter
/// </summary>
internal string Adapter { get ; private set ; }
/// <summary>
/// Gets the physical address (MAC) of the adapter
/// </summary>
internal string PhysicalAddress { get ; private set ; }
/// <summary>
/// Gets a value indicating the interface type
/// </summary>
internal NetworkInterfaceType Type { get ; private set ; }
/// <summary>
/// Gets the speed of the adapter as unformatted value (Static information form the adapter device)
/// </summary>
internal long Speed { get ; private set ; }
/// <summary>
/// Gets a value indicating the operational state of the adapter
/// </summary>
internal OperationalStatus State { get ; private set ; }
/// <summary>
/// Gets the name of the network connection
/// </summary>
internal string ConnectionName { get ; private set ; }
/// <summary>
/// Gets a string with the suffix of the connection
/// </summary>
internal string Suffix { get ; private set ; }
/// <summary>
/// Gets the IPv4 address
/// </summary>
internal string IPv4 { get ; private set ; }
/// <summary>
/// Gets the IPv4 subnet mask
/// </summary>
internal string IPv4Mask { get ; private set ; }
/// <summary>
/// Gets the primarily used IPv6 address
/// </summary>
internal string IPv6Primary { get ; private set ; }
/// <summary>
/// Gets the global IPv6 address
/// </summary>
internal string IPv6Global { get ; private set ; }
/// <summary>
/// Gets the temporary IPv6 address
/// </summary>
internal string IPv6Temporary { get ; private set ; }
/// <summary>
/// Gets the link local IPv6 address
/// </summary>
internal string IPv6LinkLocal { get ; private set ; }
/// <summary>
/// Gets the site local IPv6 address
/// </summary>
internal string IPv6SiteLocal { get ; private set ; }
/// <summary>
/// Gets the unique local IPv6 address
/// </summary>
internal string IPv6UniqueLocal { get ; private set ; }
/// <summary>
/// Gets the list of gateway IPs as string
/// </summary>
2022-04-04 13:47:58 +02:00
internal List < IPAddress > Gateways { get ; private set ; } = new List < IPAddress > ( ) ;
2022-03-21 13:37:51 +01:00
/// <summary>
/// Gets the list of DHCP server IPs as string
/// </summary>
2022-04-04 13:47:58 +02:00
internal IPAddressCollection DhcpServers { get ; private set ; }
2022-03-21 13:37:51 +01:00
/// <summary>
/// Gets the list of DNS server IPs as string
/// </summary>
2022-04-04 13:47:58 +02:00
internal IPAddressCollection DnsServers { get ; private set ; }
2022-03-21 13:37:51 +01:00
/// <summary>
/// Gets the list of WINS server IPs as string
/// </summary>
2022-04-04 13:47:58 +02:00
internal IPAddressCollection WinsServers { get ; private set ; }
2022-03-21 13:37:51 +01:00
2023-12-28 13:37:13 +03:00
private static readonly CompositeFormat MicrosoftPluginSysGbps = CompositeFormat . Parse ( Properties . Resources . Microsoft_plugin_sys_Gbps ) ;
private static readonly CompositeFormat MicrosoftPluginSysMbps = CompositeFormat . Parse ( Properties . Resources . Microsoft_plugin_sys_Mbps ) ;
2022-03-21 13:37:51 +01:00
/// <summary>
/// Initializes a new instance of the <see cref="NetworkConnectionProperties"/> class.
2022-04-04 13:47:58 +02:00
/// This private constructor is used when we crete the list of adapter (properties) by calling <see cref="NetworkConnectionProperties.GetList()"/>.
2022-03-21 13:37:51 +01:00
/// </summary>
/// <param name="networkInterface">Network interface of the connection</param>
2022-04-04 13:47:58 +02:00
private NetworkConnectionProperties ( NetworkInterface networkInterface )
2022-03-21 13:37:51 +01:00
{
// 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 ( ) ) ;
}
}
2022-04-04 13:47:58 +02:00
/// <summary>
/// Creates a list with all network adapters and their properties
/// </summary>
/// <returns>List containing all network adapters</returns>
internal static List < NetworkConnectionProperties > GetList ( )
{
2023-09-04 11:16:58 -04:00
var interfaces = NetworkInterface . GetAllNetworkInterfaces ( )
. Where ( x = > x . NetworkInterfaceType ! = NetworkInterfaceType . Loopback & & x . GetPhysicalAddress ( ) ! = null )
. Select ( i = > new NetworkConnectionProperties ( i ) )
. OrderByDescending ( i = > i . IPv4 ) // list IPv4 first
. ThenBy ( i = > i . IPv6Primary ) // then IPv6
. ToList ( ) ;
return interfaces ;
2022-04-04 13:47:58 +02:00
}
2022-03-21 13:37:51 +01:00
/// <summary>
/// Gets a formatted string with the adapter details
/// </summary>
/// <returns>String with the details</returns>
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}" ;
}
/// <summary>
/// Returns a formatted string with the connection details
/// </summary>
/// <returns>String with the details</returns>
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)}" ;
}
/// <summary>
/// Set the ip address properties of the <see cref="NetworkConnectionProperties"/> instance.
/// </summary>
/// <param name="properties">Element of the type <see cref="IPInterfaceProperties"/>.</param>
private void SetIpProperties ( IPInterfaceProperties properties )
{
2022-04-04 13:47:58 +02:00
DateTime t = DateTime . Now ;
UnicastIPAddressInformationCollection ipList = properties . UnicastAddresses ;
GatewayIPAddressInformationCollection gwList = properties . GatewayAddresses ;
DhcpServers = properties . DhcpServerAddresses ;
DnsServers = properties . DnsAddresses ;
WinsServers = properties . WinsServersAddresses ;
2022-03-21 13:37:51 +01:00
2022-04-04 13:47:58 +02:00
for ( int i = 0 ; i < ipList . Count ; i + + )
2022-03-21 13:37:51 +01:00
{
2022-04-04 13:47:58 +02:00
IPAddress ip = ipList [ i ] . Address ;
if ( ip . AddressFamily = = AddressFamily . InterNetwork )
2022-03-21 13:37:51 +01:00
{
2022-04-04 13:47:58 +02:00
IPv4 = ip . ToString ( ) ;
IPv4Mask = ipList [ i ] . IPv4Mask . ToString ( ) ;
2022-03-21 13:37:51 +01:00
}
2022-04-04 13:47:58 +02:00
else if ( ip . AddressFamily = = AddressFamily . InterNetworkV6 )
2022-03-21 13:37:51 +01:00
{
if ( string . IsNullOrEmpty ( IPv6Primary ) )
{
2022-04-04 13:47:58 +02:00
IPv6Primary = ip . ToString ( ) ;
2022-03-21 13:37:51 +01:00
}
2022-04-04 13:47:58 +02:00
if ( ip . IsIPv6LinkLocal )
2022-03-21 13:37:51 +01:00
{
2022-04-04 13:47:58 +02:00
IPv6LinkLocal = ip . ToString ( ) ;
2022-03-21 13:37:51 +01:00
}
2022-04-04 13:47:58 +02:00
else if ( ip . IsIPv6SiteLocal )
2022-03-21 13:37:51 +01:00
{
2022-04-04 13:47:58 +02:00
IPv6SiteLocal = ip . ToString ( ) ;
2022-03-21 13:37:51 +01:00
}
2022-04-04 13:47:58 +02:00
else if ( ip . IsIPv6UniqueLocal )
2022-03-21 13:37:51 +01:00
{
2022-04-04 13:47:58 +02:00
IPv6UniqueLocal = ip . ToString ( ) ;
2022-03-21 13:37:51 +01:00
}
2022-04-04 13:47:58 +02:00
else if ( ipList [ i ] . SuffixOrigin = = SuffixOrigin . Random )
2022-03-21 13:37:51 +01:00
{
2022-09-16 11:54:58 +03:00
IPv6Temporary = ip . ToString ( ) ;
2022-03-21 13:37:51 +01:00
}
else
{
2022-04-04 13:47:58 +02:00
IPv6Global = ip . ToString ( ) ;
2022-03-21 13:37:51 +01:00
}
}
}
2022-04-04 13:47:58 +02:00
for ( int i = 0 ; i < gwList . Count ; i + + )
2022-03-21 13:37:51 +01:00
{
2022-04-04 13:47:58 +02:00
Gateways . Add ( gwList [ i ] . Address ) ;
2022-03-21 13:37:51 +01:00
}
2022-04-04 13:47:58 +02:00
Debug . Print ( $"time for getting ips: {DateTime.Now - t}" ) ;
2022-03-21 13:37:51 +01:00
}
/// <summary>
/// Gets the interface type as string
/// </summary>
/// <param name="type">The type to convert</param>
/// <returns>A string indicating the interface type</returns>
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 ;
}
}
/// <summary>
/// Gets the speed as formatted text value
/// </summary>
/// <param name="speed">The adapter speed as <see langword="long"/>.</param>
/// <returns>A formatted string like `100 MB/s`</returns>
private static string GetFormattedSpeedValue ( long speed )
{
2023-12-28 13:37:13 +03:00
return ( speed > = 1000000000 ) ? string . Format ( CultureInfo . InvariantCulture , MicrosoftPluginSysGbps , speed / 1000000000 ) : string . Format ( CultureInfo . InvariantCulture , MicrosoftPluginSysMbps , speed / 1000000 ) ;
2022-03-21 13:37:51 +01:00
}
/// <summary>
/// Returns IP info or an empty string
/// </summary>
/// <param name="title">Descriptive header for the information.</param>
/// <param name="property">IP value as <see cref="string"/> or <see cref="List{String}"/>.</param>
/// <returns>Formatted string or an empty string.</returns>
/// <exception cref="ArgumentException">If the parameter <paramref name="property"/> is not of the type <see cref="string"/> or <see cref="List{String}"/>.</exception>
private static string CreateIpInfoForDetailsText ( string title , dynamic property )
{
2022-04-04 13:47:58 +02:00
switch ( property )
2022-03-21 13:37:51 +01:00
{
2022-04-04 13:47:58 +02:00
case string :
return $"\n{title}{property}" ;
case List < string > listString :
return listString . Count = = 0 ? string . Empty : $"\n{title}{string.Join(" \ n \ t ", property)}" ;
case List < IPAddress > listIP :
return listIP . Count = = 0 ? string . Empty : $"\n{title}{string.Join(" \ n \ t ", property)}" ;
case IPAddressCollection collectionIP :
return collectionIP . Count = = 0 ? string . Empty : $"\n{title}{string.Join(" \ n \ t ", property)}" ;
case null :
return string . Empty ;
default :
throw new ArgumentException ( $"'{property}' is not of type 'string', 'List<string>', 'List<IPAddress>' or 'IPAddressCollection'." , nameof ( property ) ) ;
2022-03-21 13:37:51 +01:00
}
}
}
}