In this article, we will learn what is a remote host IP address and explore different ways to extract it in ASP.NET Core Web API.
Let’s start.
What Is the Remote Host IP Address?
In general, the remote host IP address is the IP address of the client that is making a request to a web server. Retrieving this information can be useful to us for several reasons:
- Logging: we can include that information in logging to track requests and monitor the traffic of our APIs
- Security: we can use it for security purposes, such as to identify and block malicious IP addresses
- Geolocation: we can use it to determine the geographic location of the client making the request
- Analytics: to collect data for analytics purposes
When working with IP addresses, we can encounter them as IPv4
or IPv6
types. One of the differences is that IPv4 stores IP addresses as 32-bit and IPv6 as 128-bit values. Also, IPv4 addresses are typically written in dotted-decimal notation while IPv6 uses hexadecimal notation.
One example of an IP address of IPv4 type would be 192.0.2.1
and of IPv6 type 2001:0db8:85a3:0000:0000:8a2e:0370:7334
.
Now that we know a bit more about remote host IP addresses and why we may need them, let’s see how to get them!Â
How to Get the Remote Host IP Address
We will start by creating a new ASP.NET Core Web API project. We can do it using the ASP.NET Core Web Api template in Visual Studio, or using .NET CLI:
dotnet new webapi
This project template comes with a WeatherForecastController
class by default and one Get()
method that returns an array of WeatherForecastData
. We will expand this method to also capture the remote host IP address, and write it to the console.
When trying to get the remote host IP address information, we need to take into consideration intermediate devices that may modify or mask it on the way. Some of these devices can be proxies, firewalls, load balancers, or other network devices. Due to the variety of them and their setup, we have multiple ways to fetch the remote host IP address.
Knowing this, let’s now dive into the first approach we can take.
Using the RemoteIpAddressÂ
The simplest and most forward solution we can use is to check the RemoteIpAddress
property of HttpContext
:
public IPAddress? GetRemoteHostIpAddressUsingRemoteIpAddress(HttpContext httpContext) { return httpContext.Connection.RemoteIpAddress; }
The HttpContext
object represents the current HTTP request being handled by the ASP.NET Core server, we can access it using different ways mentioned in the official documentation. By using its Connection
property, we obtain the underlying ConnectionInfo
object which gives us details about the network connection associated with the current request.
Here, we can also find RemoteIpAddress
property that gives us information about the IP address of the client that initiated the HTTP request.
If we run this method locally, we can see that the fetched IP address is ::1
. This happens because the request comes from the same machine as the web server and we get the loopback address. For the IPv6 type loopback address is ::1
, and for the IPv4 address type it’s 127.0.0.1
.
In scenarios where the HTTP request is routed through proxies or load balancers, the RemoteIpAddress
property may return null
. In these cases, it may be necessary to use the X-Forwarded-For
or X-Real-IP
headers to retrieve the original client IP address, so let’s check them out.
Using “X-Forwarded-For”
The X-Forwarded-For
header is a standard HTTP header that a client can include in a request to a web server. We commonly use it in situations where the client is located behind a proxy server, firewall, or load balancer. This header value contains a comma-separated list of IP addresses:
<client>, <proxy1>, <proxy2>,...
Inside it, the leftmost IP address typically represents the original client IP address. The other IP addresses in the list represent the addresses of any intermediary proxies or load balancers that the request passed through:
public IPAddress? GetRemoteHostIpAddressUsingXForwardedFor(HttpContext httpContext) { IPAddress? remoteIpAddress = null; var forwardedFor = httpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault(); if (!string.IsNullOrEmpty(forwardedFor)) { var ips = forwardedFor.Split(',', StringSplitOptions.RemoveEmptyEntries) .Select(s => s.Trim()); foreach (var ip in ips) { if (IPAddress.TryParse(ip, out var address) && (address.AddressFamily is AddressFamily.InterNetwork or AddressFamily.InterNetworkV6)) { remoteIpAddress = address; break; } } } return remoteIpAddress; }
First, we try to retrieve the value of the header from the current HTTP request’s headers. Since its value is a list, if present, we split it by commas and trim each resulting IP address. Also, we get rid of any empty strings that could be inside.
We then iterate over each IP address and use the TryParse()
method to check for valid IP addresses. Also, we include a check that the IP address is a valid IPv4 or IPv6 type by checking that the AddressFamily
is InterNetwork
or InterNetworkV6
.
We do these checks as a form of safety measure to make sure that we are obtaining a valid IP address. This is important because headers can be manipulated, and some proxies may include additional commas or spaces, resulting in empty strings that we want to avoid.
Finally, we return the remoteIpAddress
variable, which will be the first left-most valid IPv4 or IPv6 address found in the X-Forwarded-For
header. In case no such address is present, the method will return a null.
Using “X-Real-IP” to Retrieve Remote Host IP
One more way we can go about fetching the remote host IP address is to use X-Real-IP
a header. Its value is the IP address of the client that originated the request. Also, it is common to encounter this header when working with a reverse proxy or load balancer:
public IPAddress? GetRemoteHostIpAddressUsingXRealIp(HttpContext httpContext) { IPAddress? remoteIpAddress = null; var xRealIpExists = httpContext.Request.Headers.TryGetValue("X-Real-IP", out var xRealIp); if(xRealIpExists) { if (!IPAddress.TryParse(xRealIp, out IPAddress? address)) { return remoteIpAddress; } var isValidIP = (address.AddressFamily is AddressFamily.InterNetwork or AddressFamily.InterNetworkV6); if (isValidIP) { remoteIpAddress = address; } return remoteIpAddress; } return remoteIpAddress; }
Similar to the previous method, we try to retrieve a value for X-Real-IP
header from the headers of the current HTTP request. Since it contains only one IP address if existing, we immediately check if it is a valid address and a valid type. Again, we return a valid IP address from the method, or null if such address is not found.
It’s worth noting that the use of the X-Real-IP
header is not standardized, and there is no official HTTP specification that defines it.Â
In our examples, we have used HttpContext
to get the HTTP headers but there are different ways to extract custom headers in ASP.Net core.
When to Use Which Approach?
Now we have seen some of the possible approaches to get the remote host IP address, which one to use depends on our specific network infrastructure, but there are some general guidelines we can follow.
If we are not using any network device, the simplest approach to obtain the remote host IP address is to use the RemoteIpAddress
property. However, if the API is running behind some network device, we may need to take a look at the headers.
In this case, it is important to understand which headers are we using and how we can modify them along the way. Knowing this, we can search for the correct header and extract the remote host IP address accordingly. Also, as we already mentioned, we should not trust headers blindly since their values can be tampered with or altered along the way.
Conclusion
In this article, we learned what is the remote host IP address and learned how to retrieve it. Also, we learned some general guidelines on when to use which approach.