NTP request takes a very long time while transmitting an invalid hostname

I am using the code below to request an NTP server. This code works fine until I pass in an invalid hostname for the NTP server: then this code takes a very long time.

const string ntpServer = "pool.ntp.org";

var ntpData = new byte[48];           
ntpData[0] = 0x1B; //LeapIndicator = 0 (no warning), VersionNum = 3 (IPv4 only), Mode = 3 (Client Mode)       

var addresses = Dns.GetHostEntry(ntpServer).AddressList;            
var ipEndPoint = new IPEndPoint( addresses[0] , 123);
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,  ProtocolType.Udp);    

socket.Connect(ipEndPoint);
socket.Send(ntpData);
socket.Receive(ntpData);
socket.Close();

ulong intPart = (ulong)ntpData[40] << 24 | (ulong)ntpData[41] << 16 | (ulong)ntpData[42] << 8 | (ulong)ntpData[43];
ulong fractPart = (ulong)ntpData[44] << 24 | (ulong)ntpData[45] << 16 | (ulong)ntpData[46] << 8 | (ulong)ntpData[47];

var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
var networkDateTime = (new DateTime(1900, 1, 1)).AddMilliseconds((long)milliseconds);
Label1.Text = networkDateTime.ToString();

      

I am getting the following error

show following error msgServer Error in '/' Application. No such host is known. Description: An unhandled exception was thrown during the execution of the current web request. Review the stack trace for more information about the error and how it occurs in your code. Exception Details: System.Net.Sockets.SocketException: No such host is known. Source error: line 26: ntpData [0] = 0x1B; // LeapIndicator = 0 (no warning),

+3


source to share


1 answer


UPDATE - New information

Ah, the wait you get is probably due to the timing of the DNS trying to resolve the host address.

The error you are receiving is probably due to the fact that the domain name cannot be resolved.

It's a good idea to start writing security code. Where it is possible for something to be null, throwing an exception or making an assumption.

Original Answer



UDP is a connectionless protocol that has no built-in error handling.

Since your code is using UDP, it doesn't know if it successfully sent the request to the NTP server or not, and will wait forever for a response by default. I am assuming you are killing the process yourself.

The only thing you can do is set ReceiveTimeout

and catch an exception if this happens.

const string ntpServer = "pool.ntp.org";
const int timeout = 2000;

var ntpData = new byte[48];           
ntpData[0] = 0x1B; //LeapIndicator = 0 (no warning), VersionNum = 3 (IPv4 only), Mode = 3 (Client Mode)       

IPHostEntry dnsLookup = null;
try {
    dnsLookup = Dns.GetHostEntry(ntpServer);
}
catch(Exception e){ //Better to catch specific types of exceptions
    Label1.Text = string.Format("Unable to resolve hostname: {0}, ntpServer)";
}

if (dnsLookup == null || dnsLookup.AddressList.Length == 0){
    return;
}

var ipEndPoint = new IPEndPoint(dnsLookup.AddressList[0], 123);
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,  ProtocolType.Udp);    

// wait two seconds before timing out
socket.ReceiveTimeout = timeout; 

try{
    socket.Connect(ipEndPoint);
    socket.Send(ntpData);

    socket.Receive(ntpData);
    ulong intPart = (ulong)ntpData[40] << 24 | (ulong)ntpData[41] << 16 | (ulong)ntpData[42] << 8 | (ulong)ntpData[43];
    ulong fractPart = (ulong)ntpData[44] << 24 | (ulong)ntpData[45] << 16 | (ulong)ntpData[46] << 8 | (ulong)ntpData[47];

    var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
    var networkDateTime = (new DateTime(1900, 1, 1)).AddMilliseconds((long)milliseconds);
    Label1.Text = networkDateTime.ToString();
}
catch(Exception e){ //Better to catch specific types of exceptions
    Label1.Text = string.Format("Unable to get time from NTP server: {0}, ntpServer)";
}
finally{
    socket.Close();
}

      

+3


source







All Articles