Retrieving Subnet Mask Address From .NET HttpRequest class - c#

Giving an object instance from the class System.Web.HttpRequest, say myRequest, then using the property System.Web.HttpRequest.UserHostAddress I can retrieve the IP address of the remote client:
string myIp = myRequest.UserHostAddress;
(...)
My need is to retrieve the IP address of the subnet mask of the remote client exclusively from the instance myRequest.
I know that the following is not possible but I would like to accomplish something similar:
string myMaskIp = myRequest.UserHostMaskAddress;
(...)
This because I can't check the local device network interfaces as I could with System.Net.NetworkInformation namespace, so my only available object to probe is the http request made from the remote client to the server.
Thank you very much for your help

I'm pretty sure you can not determine a subnet mask by simply making a request to a remote host - even if the remote host is you.

Oldyis is right for the general case, however it is possible to determine a classful subnetmask from the IPv4 address. Without any further information, determining an classless subnetmask is indeed impossible.
Keep in mind that the classful adressing scheme is virtually not used any more.
Here is an example from this project:
/// <summary>
/// Returns the classfull subnet mask of a given IPv4 network
/// </summary>
/// <param name="ipa">The network to get the classfull subnetmask for</param>
/// <returns>The classfull subnet mask of a given IPv4 network</returns>
public static Subnetmask GetClassfullSubnetMask(IPAddress ipa)
{
if (ipa.AddressFamily != AddressFamily.InterNetwork)
{
throw new ArgumentException("Only IPv4 addresses are supported for classfull address calculations.");
}
IPv4AddressClass ipv4Class = GetClass(ipa);
Subnetmask sm = new Subnetmask();
if (ipv4Class == IPv4AddressClass.A)
{
sm.MaskBytes[0] = 255;
}
if (ipv4Class == IPv4AddressClass.B)
{
sm.MaskBytes[0] = 255;
sm.MaskBytes[1] = 255;
}
if (ipv4Class == IPv4AddressClass.C)
{
sm.MaskBytes[0] = 255;
sm.MaskBytes[1] = 255;
sm.MaskBytes[2] = 255;
}
return sm;
}
(Think of the SubnetMask class as a byte array of length four)

Related

Client IP address returns the same internal network address

I'm trying to get the user's IP address from ASP.NET MVC 5. I've looked up various examples, such as these:
https://stackoverflow.com/a/740431/177416
https://stackoverflow.com/a/20194511/177416
https://stackoverflow.com/a/3003254/177416
They've all produced the same result: the user is considered internal to the network. I've had friends try their phones (which are not on the network). Here's my latest attempt:
private static Logger _logger = LogManager.GetCurrentClassLogger();
public static bool IsIpInternal()
{
var ipAddress = HttpContext.Current.Request.UserHostAddress;
var logEvent = new LogEventInfo(LogLevel.Info, _logger.Name, ipAddress);
_logger.Log(logEvent);
try
{
if (ipAddress != null)
{
var ipParts = ipAddress.Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries)
.Select(int.Parse).ToArray();
var isDebug = System.Diagnostics.Debugger.IsAttached;
if (ipParts[0] == 10)
{
return true;
}
}
}
catch (Exception e)
{
logEvent = new LogEventInfo(LogLevel.Error, _logger.Name, e.Message);
_logger.Log(logEvent);
return false;
}
return false;
}
The log is showing 10.xxx.xx.xxx for all requests (based on the log). This is an internal address rather than the IP of the client connecting to the web app. The IsIpInternal() returns true always. What am I doing wrong?
Note that I'm ignoring 192.168.x.x and 172.16.xxx.xxx addresses as being internal.
If your web site is behind a load balancer, it is a common problem for the load balancer's IP address to appear when you are expecting the client's IP address. That is because in reality the load balancer is the only client that the web application knows is talking to it.
There are two ways to deal with this:
You can configure the load balancer to add an additional HTTP header (x-forwarded-for) that specifies the original IP address. You will need to modify your web site to look at this header instead of the UserHostAddress, like this:
//var clientIP = HttpContext.Current.Request.UserHostAddress;
var clientIP = HttpContext.Current.Request.Headers["x-forwarded-for"];
Note: The x-forwarded-for header can actually return a comma-delimited list of IP addresses in some cases. So to be compatible with such an occurence, you might write this instead:
var clientIP = HttpContext.Current.Request.Headers["x-forwarded-for"].Split(',')[0];
You can configure certain LBs to pass through the client IP by copying the IP header packet. For Citrix Netscaler, see this article for more information.

Resolving an IP address from DNS in C# [duplicate]

This question already has answers here:
Can't parse domain into IP in C#?
(6 answers)
Closed 9 years ago.
I am trying to make a TCP socket connection to an IP address. I can do this by directly parsing an IP address like this:
IPAddress ipAddress = IPAddress.Parse("192.168.1.123");
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 80);
// Create a TCP/IP socket.
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // This works!
However, I cannot figure out how to divine this IP address from a DNS string. I've tried every combination of the following:
IPAddress ipAddress = Dns.Resolve("www.mydns.org"); // No dice
IPAddress ipAddress = Dns.GetHostEntry("www.mydns.org"); // Nada
IPAddress ipAddress = IPAddress.Parse(Dns.Resolve("www.mydns.org")); // So many errors...
IPAddress ipAddress = IPAddress.Parse(Dns.Resolve("www.mydns.org").toString()); // WTh is this attempt anyway?
Would any of you kind souls have a tip to help me squeeze an IPAddress out of a DNS?
foreach (IPAddress ip in Dns.GetHostAddresses("www.mydns.org"))
{
Console.WriteLine(ip.ToString());
}
or simply IPAddress address = Dns.GetHostAddresses("www.mydns.org")[0]; if you want the first one only.
I've got a very neat extension method for just that!
I takes into account that an IPV6 may be returned as the first address in the list of addresses returned by the DNS class and allows you to "favor" an IPV6 or IPV4 on the result. Here is the fully documented class (only with the pertinent method for this case for reasons of brevity):
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
/// <summary>
/// Basic helper methods around networking objects (IPAddress, IpEndPoint, Socket, etc.)
/// </summary>
public static class NetworkingExtensions
{
/// <summary>
/// Converts a string representing a host name or address to its <see cref="IPAddress"/> representation,
/// optionally opting to return a IpV6 address (defaults to IpV4)
/// </summary>
/// <param name="hostNameOrAddress">Host name or address to convert into an <see cref="IPAddress"/></param>
/// <param name="favorIpV6">When <code>true</code> will return an IpV6 address whenever available, otherwise
/// returns an IpV4 address instead.</param>
/// <returns>The <see cref="IPAddress"/> represented by <paramref name="hostNameOrAddress"/> in either IpV4 or
/// IpV6 (when available) format depending on <paramref name="favorIpV6"/></returns>
public static IPAddress ToIPAddress(this string hostNameOrAddress, bool favorIpV6=false)
{
var favoredFamily = favorIpV6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork;
var addrs = Dns.GetHostAddresses(hostNameOrAddress);
return addrs.FirstOrDefault(addr => addr.AddressFamily == favoredFamily)
??
addrs.FirstOrDefault();
}
}
Don't forget to put this class inside a namespace! :-)
Now you can simply do this:
var server = "http://simpax.com.br".ToIPAddress();
var blog = "http://simpax.codax.com.br".ToIPAddress();
var google = "google.com.br".ToIPAddress();
var ipv6Google = "google.com.br".ToIPAddress(true); // if available will be an IPV6
IPHostEntry entry = Dns.GetHostEntry(hostNameOrAddress: "www.google.com");
foreach (IPAddress addr in entry.AddressList)
{
// connect, on sucess call 'break'
}
Simply enumerate address by calling GetHostEntry, on sucess break the loop

tcp/ip packet listener

I've started to do some basic network programming.
I have read/written my own programs using TcpClient and TcpListener and that has worked fine.
However, the application I am working on now works a bit differently.
I want to set up a program that listens for tcp/ip packets without having to connect.
For example, have a packet sending app send a packet to my program with the appropriate ip add and port number.
I have also looked into using Sharppcap and packet.net but all of the examples I've found only listens on devices found locally (no opportunity to set parameters such as port number and ip add).
Does anyone have a suggestion on how to go about doing this?
You should look at using the UDP protocol instead of TCP/IP.
http://en.wikipedia.org/wiki/User_Datagram_Protocol
Here is the code for the client:
using System.Net;
using System.Net.Sockets;
...
/// <summary>
/// Sends a sepcified number of UDP packets to a host or IP Address.
/// </summary>
/// <param name="hostNameOrAddress">The host name or an IP Address to which the UDP packets will be sent.</param>
/// <param name="destinationPort">The destination port to which the UDP packets will be sent.</param>
/// <param name="data">The data to send in the UDP packet.</param>
/// <param name="count">The number of UDP packets to send.</param>
public static void SendUDPPacket(string hostNameOrAddress, int destinationPort, string data, int count)
{
// Validate the destination port number
if (destinationPort < 1 || destinationPort > 65535)
throw new ArgumentOutOfRangeException("destinationPort", "Parameter destinationPort must be between 1 and 65,535.");
// Resolve the host name to an IP Address
IPAddress[] ipAddresses = Dns.GetHostAddresses(hostNameOrAddress);
if (ipAddresses.Length == 0)
throw new ArgumentException("Host name or address could not be resolved.", "hostNameOrAddress");
// Use the first IP Address in the list
IPAddress destination = ipAddresses[0];
IPEndPoint endPoint = new IPEndPoint(destination, destinationPort);
byte[] buffer = Encoding.ASCII.GetBytes(data);
// Send the packets
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
for(int i = 0; i < count; i++)
socket.SendTo(buffer, endPoint);
socket.Close();
}

Can't parse domain into IP in C#?

I have this code:
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(txtBoxIP.Text), MainForm.port);
When I have an IP in the txtBoxIP (192.168.1.2) for example, it works great.
But if I want to put a DNS? like I'm putting (my.selfip.com) I get:
System.FormatException: An invalid IP address was specified.
at System.Net.IPAddress.InternalParse(String ipString, Boolean tryParse)
How can I make it support both IP and DNS ?
IPAddress ipAddress;
if (!IPAddress.TryParse (txtBoxIP.Text, out ipAddress))
ipAddress = Dns.GetHostEntry (txtBoxIP.Text).AddressList[0];
serverEndPoint = new IPEndPoint(ipAddress, MainForm.port)
Don't forget the error handling.
A DNS name isn't an IP address. Look at Dns.GetHostEntry() for DNS resolution.
Edited to add: Here's what I've done:
public static IPEndPoint CreateEndpoint( string hostNameOrAddress , int port )
{
IPAddress addr ;
bool gotAddr = IPAddress.TryParse( hostNameOrAddress , out addr ) ;
if ( !gotAddr )
{
IPHostEntry dnsInfo = Dns.GetHostEntry( hostNameOrAddress ) ;
addr = dnsInfo.AddressList.First() ;
}
IPEndPoint instance = new IPEndPoint( addr , port ) ;
return instance ;
}
DNS to IP List
IPHostEntry nameToIpAddress;
nameToIpAddress = Dns.GetHostEntry("HostName");
foreach (IPAddress address in nameToIpAddress.AddressList)
Console.WriteLine(address.ToString());
Then you can use the IP's in the AddressList.
Here is a great article
var input = txtBoxIP.Text;
IPAddress ip;
// TryParse returns true when IP is parsed successfully
if (!IPAddress.TryParse (input, out ip))
// in case user input is not an IP, assume it's a hostname
ip = Dns.GetHostEntry (input).AddressList [0]; // you may use the first one
// note that you'll also want to handle input errors
// such as invalid strings that are neither IPs nor valid domains,
// as well as hosts that couldn't be resolved
var serverEndPoint = new IPEndPoint (ip, MainForm.port);
Note: No, it is not déjà vu, this answer is the exact same I provided on another duplicate question... I wanted to make the author of this one aware of the other so the best way I've found was to add it again here as just linking to other answers is frowned upon on Stack Overflow.
I've got a very neat extension method for just that!
I takes into account that an IPV6 may be returned as the first address in the list of addresses returned by the DNS class and allows you to "favor" an IPV6 or IPV4 on the result. Here is the fully documented class (only with the pertinent method for this case for reasons of brevity):
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
/// <summary>
/// Basic helper methods around networking objects (IPAddress, IpEndPoint, Socket, etc.)
/// </summary>
public static class NetworkingExtensions
{
/// <summary>
/// Converts a string representing a host name or address to its <see cref="IPAddress"/> representation,
/// optionally opting to return a IpV6 address (defaults to IpV4)
/// </summary>
/// <param name="hostNameOrAddress">Host name or address to convert into an <see cref="IPAddress"/></param>
/// <param name="favorIpV6">When <code>true</code> will return an IpV6 address whenever available, otherwise
/// returns an IpV4 address instead.</param>
/// <returns>The <see cref="IPAddress"/> represented by <paramref name="hostNameOrAddress"/> in either IpV4 or
/// IpV6 (when available) format depending on <paramref name="favorIpV6"/></returns>
public static IPAddress ToIPAddress(this string hostNameOrAddress, bool favorIpV6=false)
{
var favoredFamily = favorIpV6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork;
var addrs = Dns.GetHostAddresses(hostNameOrAddress);
return addrs.FirstOrDefault(addr => addr.AddressFamily == favoredFamily)
??
addrs.FirstOrDefault();
}
}
Don't forget to put this class inside a namespace! :-)
Now you can simply do this:
var server = "http://simpax.com.br".ToIPAddress();
var blog = "http://simpax.codax.com.br".ToIPAddress();
var google = "google.com.br".ToIPAddress();
var ipv6Google = "google.com.br".ToIPAddress(true); // if available will be an IPV6
You'll have to look up the IP of the hostname yourself:
string addrText = "www.example.com";
IPAddress[] addresslist = Dns.GetHostAddresses(addrText);
foreach (IPAddress theaddress in addresslist)
{
Console.WriteLine(theaddress.ToString());
}
Edit
To tell the difference between the two (BTW this uses some features of C# that may be in 3.5 and above):
bool isDomain = false;
foreach(char c in addrText.ToCharArray())
{
if (char.IsLetter(c)){
isDomain = true;
break;
}
if (isDomain)
// lookup IP here
else
// parse IP here

IPv4 remote address in WCF

Related to How to get the IP address of a WCF remote endpoint?
I am using this code to retrieve the remote IP address when a workflow method is invoked:
private static string GetRemoteIP()
{
var oc = OperationContext.Current;
var mp = oc.IncomingMessageProperties;
var remp = mp[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
return remp == null ? "(unknown)" : remp.Address;
}
However, the address I get back is "::1". I don't want the IPv6 address, I want the IPv4 one (127.0.0.1) - any way of forcing this?
No, I don't think so. You basically just read out a property set by the client at the time of the call. Your only option would be to instruct the client (through some config) to use IPv4 instead of IPv6 at all times (i.e. turn off IPv6 all together).
I'm not aware of any WCF setting to enforce that - you'd have to dig into the network stack and see if there's any way to make it use IPv4 addresses instead of IPv6.
You're seeing ::1 because you're connecting to the service by resolving the name "localhost" instead of addressing it as "127.0.0.1". Modern versions of Windows that have the IPv6 stack enabled will use IPv6 first.
You can disable the IPv6 stack, but that's roughly the same as making like an ostrich and sticking your head in the sand. IPv6 is here, and people are using it on their networks, so your application should be prepared to support it.
The workaround proposed by Murat will not work.
The MSDN says - if you pass the IP address to the GetHostAddresses method this address is returned in an array without querying the DNS.
To get it working you will need to query for the host name first, using GetHostEntry method. And then, using the host name, use GetHostAddresses. However, even the GetHostEntry may have the list of addresses that will be enough for you.
Here is a workaround: (You can store the values in a hashtable to avoid multiple DNS operations)
static string GetClientIP()
{
var context = OperationContext.Current;
var mp = context.IncomingMessageProperties;
var propName = RemoteEndpointMessageProperty.Name;
var prop = (RemoteEndpointMessageProperty) mp[propName];
string remoteIP = prop.Address;
if(remoteIP.IndexOf(":") > -1)
{
IPAddress[] addresses = Dns.GetHostAddresses(remoteIP);
for (int i = 0; i < addresses.Length; i++)
{
if(addresses[i].ToString().IndexOf(".")>-1)
return addresses[i].ToString();
}
return remoteIP;
}
else
{
return remoteIP;
}
}
You could use AddressFamily.InterNetwork == address.AddressFamily and AddressFamily.InterNetworkV6 as a test instead of looking for ":" or "." in the addresses strings.

Categories