//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*/
}
}