//using Swan.Net.Dns; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; namespace Swan.Net { /// /// Provides miscellaneous network utilities such as a Public IP finder, /// a DNS client to query DNS records of any kind, and an NTP client. /// public static class Network { /*/// /// The DNS default port. /// public const Int32 DnsDefaultPort = 53; /// /// The NTP default port. /// public const Int32 NtpDefaultPort = 123;*/ /// /// Gets the name of the host. /// /// /// The name of the host. /// // [Obsolete("NEED", false)] public static String HostName => IPGlobalProperties.GetIPGlobalProperties().HostName; /*/// /// Gets the name of the network domain. /// /// /// The name of the network domain. /// public static String DomainName => IPGlobalProperties.GetIPGlobalProperties().DomainName; #region IP Addresses and Adapters Information Methods /// /// Gets the active IPv4 interfaces. /// Only those interfaces with a valid unicast address and a valid gateway will be returned in the collection. /// /// /// A collection of NetworkInterface/IPInterfaceProperties pairs /// that represents the active IPv4 interfaces. /// public static Dictionary GetIPv4Interfaces() { // zero conf ip address IPAddress zeroConf = new IPAddress(0); NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces().Where(network => network.OperationalStatus == OperationalStatus.Up && network.NetworkInterfaceType != NetworkInterfaceType.Unknown && network.NetworkInterfaceType != NetworkInterfaceType.Loopback).ToArray(); Dictionary result = new Dictionary(); foreach(NetworkInterface adapter in adapters) { IPInterfaceProperties properties = adapter.GetIPProperties(); if(properties == null || properties.GatewayAddresses.Count == 0 || properties.GatewayAddresses.All(gateway => Equals(gateway.Address, zeroConf)) || properties.UnicastAddresses.Count == 0 || properties.GatewayAddresses.All(address => Equals(address.Address, zeroConf)) || properties.UnicastAddresses.Any(a => a.Address.AddressFamily == AddressFamily.InterNetwork) == false) { continue; } result[adapter] = properties; } return result; } /// /// Retrieves the local ip addresses. /// /// if set to true [include loopback]. /// An array of local ip addresses. public static IPAddress[] GetIPv4Addresses(Boolean includeLoopback = true) => GetIPv4Addresses(NetworkInterfaceType.Unknown, true, includeLoopback); /// /// Retrieves the local ip addresses. /// /// Type of the interface. /// if set to true [skip type filter]. /// if set to true [include loopback]. /// An array of local ip addresses. public static IPAddress[] GetIPv4Addresses(NetworkInterfaceType interfaceType, Boolean skipTypeFilter = false, Boolean includeLoopback = false) { List addressList = new List(); NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces() .Where(ni => (skipTypeFilter || ni.NetworkInterfaceType == interfaceType) && ni.OperationalStatus == OperationalStatus.Up).ToArray(); foreach(NetworkInterface networkInterface in interfaces) { IPInterfaceProperties properties = networkInterface.GetIPProperties(); if(properties.GatewayAddresses.All(g => g.Address.AddressFamily != AddressFamily.InterNetwork)) { continue; } addressList.AddRange(properties.UnicastAddresses.Where(i => i.Address.AddressFamily == AddressFamily.InterNetwork).Select(i => i.Address)); } if(includeLoopback || interfaceType == NetworkInterfaceType.Loopback) { addressList.Add(IPAddress.Loopback); } return addressList.ToArray(); } /// /// Gets the public IP address using ipify.org. /// /// The cancellation token. /// A public IP address of the result produced by this Task. public static async Task GetPublicIPAddressAsync(CancellationToken cancellationToken = default) { using HttpClient client = new HttpClient(); HttpResponseMessage response = await client.GetAsync("https://api.ipify.org", cancellationToken).ConfigureAwait(false); return IPAddress.Parse(await response.Content.ReadAsStringAsync().ConfigureAwait(false)); } /// /// Gets the configured IPv4 DNS servers for the active network interfaces. /// /// /// A collection of NetworkInterface/IPInterfaceProperties pairs /// that represents the active IPv4 interfaces. /// public static IPAddress[] GetIPv4DnsServers() => GetIPv4Interfaces().Select(a => a.Value.DnsAddresses.Where(d => d.AddressFamily == AddressFamily.InterNetwork)).SelectMany(d => d).ToArray(); #endregion #region DNS and NTP Clients /// /// Gets the DNS host entry (a list of IP addresses) for the domain name. /// /// The FQDN. /// An array of local ip addresses of the result produced by this task. public static Task GetDnsHostEntryAsync(String fqdn) { IPAddress dnsServer = GetIPv4DnsServers().FirstOrDefault() ?? IPAddress.Parse("8.8.8.8"); return GetDnsHostEntryAsync(fqdn, dnsServer, DnsDefaultPort); } /// /// Gets the DNS host entry (a list of IP addresses) for the domain name. /// /// The FQDN. /// The DNS server. /// The port. /// /// An array of local ip addresses of the result produced by this task. /// /// fqdn. public static async Task GetDnsHostEntryAsync(String fqdn, IPAddress dnsServer, Int32 port) { if(fqdn == null) { throw new ArgumentNullException(nameof(fqdn)); } if(fqdn.IndexOf(".", StringComparison.Ordinal) == -1) { fqdn += "." + IPGlobalProperties.GetIPGlobalProperties().DomainName; } while(true) { if(!fqdn.EndsWith(".", StringComparison.OrdinalIgnoreCase)) { break; } fqdn = fqdn[0..^1]; } DnsClient client = new DnsClient(dnsServer, port); IList result = await client.Lookup(fqdn).ConfigureAwait(false); return result.ToArray(); } /// /// Gets the reverse lookup FQDN of the given IP Address. /// /// The query. /// The DNS server. /// The port. /// A that represents the current object. public static Task GetDnsPointerEntryAsync(IPAddress query, IPAddress dnsServer, Int32 port) { DnsClient client = new DnsClient(dnsServer, port); return client.Reverse(query); } /// /// Gets the reverse lookup FQDN of the given IP Address. /// /// The query. /// A that represents the current object. public static Task GetDnsPointerEntryAsync(IPAddress query) { DnsClient client = new DnsClient(GetIPv4DnsServers().FirstOrDefault()); return client.Reverse(query); } /// /// Queries the DNS server for the specified record type. /// /// The query. /// Type of the record. /// The DNS server. /// The port. /// Queries the DNS server for the specified record type of the result produced by this Task. public static async Task QueryDnsAsync(String query, DnsRecordType recordType, IPAddress dnsServer, Int32 port) { if(query == null) { throw new ArgumentNullException(nameof(query)); } DnsClient client = new DnsClient(dnsServer, port); DnsClient.DnsClientResponse response = await client.Resolve(query, recordType).ConfigureAwait(false); return new DnsQueryResult(response); } /// /// Queries the DNS server for the specified record type. /// /// The query. /// Type of the record. /// Queries the DNS server for the specified record type of the result produced by this Task. public static Task QueryDnsAsync(String query, DnsRecordType recordType) => QueryDnsAsync(query, recordType, GetIPv4DnsServers().FirstOrDefault(), DnsDefaultPort); /// /// Gets the UTC time by querying from an NTP server. /// /// The NTP server address. /// The port. /// The UTC time by querying from an NTP server of the result produced by this Task. public static async Task GetNetworkTimeUtcAsync(IPAddress ntpServerAddress, Int32 port = NtpDefaultPort) { if(ntpServerAddress == null) { throw new ArgumentNullException(nameof(ntpServerAddress)); } // NTP message size - 16 bytes of the digest (RFC 2030) Byte[] ntpData = new Byte[48]; // Setting the Leap Indicator, Version Number and Mode values ntpData[0] = 0x1B; // LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode) // The UDP port number assigned to NTP is 123 IPEndPoint endPoint = new IPEndPoint(ntpServerAddress, port); Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); await socket.ConnectAsync(endPoint).ConfigureAwait(false); socket.ReceiveTimeout = 3000; // Stops code hang if NTP is blocked _ = socket.Send(ntpData); _ = socket.Receive(ntpData); socket.Dispose(); // Offset to get to the "Transmit Timestamp" field (time at which the reply // departed the server for the client, in 64-bit timestamp format." const Byte serverReplyTime = 40; // Get the seconds part UInt64 intPart = BitConverter.ToUInt32(ntpData, serverReplyTime); // Get the seconds fraction UInt64 fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4); // Convert From big-endian to little-endian to match the platform if(BitConverter.IsLittleEndian) { intPart = intPart.SwapEndianness(); fractPart = intPart.SwapEndianness(); } UInt64 milliseconds = intPart * 1000 + fractPart * 1000 / 0x100000000L; // The time is given in UTC return new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds((Int64)milliseconds); } /// /// Gets the UTC time by querying from an NTP server. /// /// The NTP server, by default pool.ntp.org. /// The port, by default NTP 123. /// The UTC time by querying from an NTP server of the result produced by this Task. public static async Task GetNetworkTimeUtcAsync(String ntpServerName = "pool.ntp.org", Int32 port = NtpDefaultPort) { IPAddress[] addresses = await GetDnsHostEntryAsync(ntpServerName).ConfigureAwait(false); return await GetNetworkTimeUtcAsync(addresses.First(), port).ConfigureAwait(false); } #endregion*/ } }