- Hands-On Network Programming with C# and .NET Core
- Sean Burns
- 982字
- 2021-06-24 16:05:17
The DNS in C#
It is occasionally necessary to identify the underlying IP address for a domain name from within the context of our software. For that, .NET Core provides the static Dns class as part of the System.Net namespace. With the Dns class, we can access directory information as returned by the nearest downstream name server capable of resolving the given name. We can request an instance of the IPHostEntry class, containing all of the relevant directory information of a DNS entry, or simply an array of IP addresses registered to resolve requests against the domain name.
To see this in action, simply invoke any of the methods exposed by the static Dns class in a sample program as follows:
using System;
using System.Net;
using System.Threading;
namespace DnsTest {
public class DnsTestProgram {
static void Main(string[] args) {
var domainEntry = Dns.GetHostEntry("google.com");
Console.WriteLine(domainEntry.HostName);
foreach(var ip in domainEntry.AddressList) {
Console.WriteLine(ip);
}
Thread.Sleep(10000);
}
}
}
With this program, we should see the following output:
google.com
172.217.10.14
Of course, the IP address that is resolved when you look for a host entry that resolves the google.com domain name will likely be different. Google's servers are widely distributed, and the specific server slice (and its associated IP address) that is nearest your network location will be what resolves a lookup of that domain name.
If you want to validate that the IP address returned is in fact what is registered for that domain name, you can actually intercept the host entry lookup locally by modifying your computer's hosts file. On a Windows OS, that file will live at the C:\Windows\System32\drivers\etc\hosts directory, and will have no file extension. On macOS and *nix systems, it simply lives at \etc\hosts.
This file serves as the first stop on any outbound requests for a network resource addressed by a host name. It is, technically, your computer's internal name server, and you can use it to direct traffic any way you'd like. To demonstrate this, add an entry to your hosts file as follows:
127.0.0.1 fun.with.dns.com
Now, opening your command prompt, navigate to an empty folder, and spin up a new .NET Core Web API project with the following CLI command:
dotnet new webapi
Your console should print information about .NET Core, telemetry, ASP.NET Core, and finally, finish execution with the following line:
Restore succeeded.
Assuming that this worked, you can immediately run the application by executing the following command from within the same directory that you created the project:
dotnet run
After this, you should see that your application is running and listening, as seen in the following screenshot:
Pay attention to the specific port your application is listening on.
If we look inside the blank Web API application, we can see that .NET Core stood up a single controller, named ValuesController, and that it exposes a number of REST endpoints. The only things that we're concerned with for now is the route specified for the API, and the endpoint listening for HTTP GET requests, listed as follows:
[Route("api/{controller}")]
...
[HttpGet("{id}")]
public ActionResult<string> Get(int id) {
return "value";
}
This tells us that we should expect to see the "value" result if we navigate to the /api/values/{id} path on the listening port of our local machine.
Sure enough, if you open your browser of choice and type the application's URL into your address bar, appending the path specified in the controller, you should see the value string displayed in your browser, as shown in the following screenshot:
What's interesting, though, is that localhost is itself an alias for the 127.0.0.1 IP address. By convention, that address always resolves to the current local machine. Since we modified our hosts file, however, we should be able to replace localhost in our URL with the fun.with.dns.com as new domain name. Make the change in your browser, and you'll see the same response!
Now that we've seen how to set up our own domain name entries locally, we can use our hosts file to explore the Dns class in more detail, and validate the responses.
First, add an additional entry to the hosts file with a new IP address, but the same fake domain name as before. Your new hosts file should read as follows:
127.0.0.1 fun.with.dns.com
1.0.0.127 fun.with.dns.com
Here, it doesn't actually matter what the addresses are, since we won't be looking for resources at those locations. What matters is that there are two. With those entries in place, you can see more concretely how the Dns class in .NET exposes a host entry from the nearest domain name server that can resolve it. We can modify our program from before as follows:
using System;
using System.Net;
namespace DnsTest {
public class DnsTestProgram {
static void Main(string[] args) {
var domainEntry = Dns.GetHostEntry("fun.with.dns.com");
Console.WriteLine(domainEntry.HostName);
foreach(var ip in domainEntry.AddressList) {
Console.WriteLine(ip);
}
var domainEntryByAddress = Dns.GetHostEntry("127.0.0.1");
Console.WriteLine(domainEntryByAddress.HostName);
foreach(var ip in domainEntryByAddress.AddressList) {
Console.WriteLine(ip);
}
Thread.Sleep(10000);
}
}
}
We can now see the following output:
fun.with.dns.com
1.0.0.127
127.0.0.1
fun.with.dns.com
1.0.0.127
127.0.0.1
This demonstrates how we can access host information for a given domain name or IP address using the Dns class. Note that the instance of the HostEntry class returned by the methods of the Dns class always contain all of the IP addresses for which there is a record in the naming server. Even when we looked up the HostEntry class by a specific IP address, the Dns class still resolved and returned every other IP address registered for the domain name that matched the IP address of the original lookup. This provides the flexibility of being able to access and leverage alternative hardware resources for a given request in the event that one of the registered addresses is unresponsive. The extent to which you'll leverage this class in your work may vary, but I hope you see now that it can be a useful tool to keep in your belt.