// 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.Diagnostics; using System.Globalization; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Text; using Microsoft.PowerToys.Run.Plugin.System.Properties; namespace Microsoft.PowerToys.Run.Plugin.System.Components { /// /// This class represents the information for a network connection/interface /// internal sealed 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 IPAddressCollection DhcpServers { get; private set; } /// /// Gets the list of DNS server IPs as string /// internal IPAddressCollection DnsServers { get; private set; } /// /// Gets the list of WINS server IPs as string /// internal IPAddressCollection WinsServers { get; private set; } 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); /// /// Initializes a new instance of the class. /// This private constructor is used when we crete the list of adapter (properties) by calling . /// /// Network interface of the connection private 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()); } } /// /// Creates a list with all network adapters and their properties /// /// List containing all network adapters internal static List GetList() { 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; } /// /// 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) { DateTime t = DateTime.Now; UnicastIPAddressInformationCollection ipList = properties.UnicastAddresses; GatewayIPAddressInformationCollection gwList = properties.GatewayAddresses; DhcpServers = properties.DhcpServerAddresses; DnsServers = properties.DnsAddresses; WinsServers = properties.WinsServersAddresses; for (int i = 0; i < ipList.Count; i++) { IPAddress ip = ipList[i].Address; if (ip.AddressFamily == AddressFamily.InterNetwork) { IPv4 = ip.ToString(); IPv4Mask = ipList[i].IPv4Mask.ToString(); } else if (ip.AddressFamily == AddressFamily.InterNetworkV6) { if (string.IsNullOrEmpty(IPv6Primary)) { IPv6Primary = ip.ToString(); } if (ip.IsIPv6LinkLocal) { IPv6LinkLocal = ip.ToString(); } else if (ip.IsIPv6SiteLocal) { IPv6SiteLocal = ip.ToString(); } else if (ip.IsIPv6UniqueLocal) { IPv6UniqueLocal = ip.ToString(); } else if (ipList[i].SuffixOrigin == SuffixOrigin.Random) { IPv6Temporary = ip.ToString(); } else { IPv6Global = ip.ToString(); } } } for (int i = 0; i < gwList.Count; i++) { Gateways.Add(gwList[i].Address); } Debug.Print($"time for getting ips: {DateTime.Now - t}"); } /// /// 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, MicrosoftPluginSysGbps, speed / 1000000000) : string.Format(CultureInfo.InvariantCulture, MicrosoftPluginSysMbps, 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) { switch (property) { case string: return $"\n{title}{property}"; case List listString: return listString.Count == 0 ? string.Empty : $"\n{title}{string.Join("\n\t", property)}"; case List 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', 'List' or 'IPAddressCollection'.", nameof(property)); } } } }