There is restriction on UDP response size for DNS protocol. It can only contain ~500bytes. When data exceeds the limit all the DNS servers sets flag "truncated" in response but some (google 8.8.8.8 for example) does not put any IPs in response others just put trimmed list. Utilities like nslookup and dig tries to ask DNS server by TCP to get full response but android does not. Instead it fails. The example of code that fails is bellow.
var host = "prdimg.affili.net";
var addressList = Dns.GetHostEntry(host).AddressList;
The Modernhttpclient uses gets IPs the same way so I cannot get files from prdimg.affili.net. To fix it I've implemented the temporary solution. I use GooglePublicDnsClient to resolve DNS and then change hostname to resolved ip with UriBuilder.
var builder = new UriBuilder(originalUrl);
builder.Host = ip;
But the solution has two disadvantages
it does not work for https because of certificate check
it does not work if server uses Vhosts
Can anyone propose a better solution?
Related
C# 4.5.2 framework HttpClient.GetAsync() method works fine on Windows 10 when system is not using VPN.
When VPN is connected HttpClient.GetAsync() call to the same address just blocks until it times out. Both Edge and Chrome have no issues accessing that same address.
Is there a way to see what is happening? What is HttpClient doing differently?
Update: Got some interesting clues by calling Dns.GetHostEntry(). Without VPN
this call returned only IPv4 addresses that all could be connected to. With VPN client connected Dns.GetHostEntry() returned additional IPv6 addresses at the top of the list. Connection to all IPv6 addresses timed out but all IPv4 ones still worked OK. Now is there a way to figure out without trying to connect which addresses work and which ones do not?
In my experience, this sounds like a VPN / firewall issue to me. One quick thing to toggle in windows is under you VPN adapter properties, try unchecking "Use default gateway on remote network" - I know it sounds like a long shot but have had this problem in the past...
Have to answer this myself as this problem has a simple cause but very confusing symptoms.
The root cause:
DNS reports only IPv4 addresses for the host when system is not connected to VPN. All IPv4 addresses are usable.
When VPN connection is active DNS returns IPv6 addresses in addition to IPv4. IPv4 addresses are still accessible but IPv6 are not.
The cause of such invalid network configuration is still a mystery that deserves its own separate post.
Confusing part:
Some apps work no matter what VPN connection status is.
"But web browser can connect to the same host with or without VPN." True. Browsers may use Happy eyeballs approach attempting to connect using both IPv4 and IPv6 at the same time.
"But my old app has not problems connecting." Also true. Some older and not so old apps use IPv4 protocol by default. Support for IPv6 or IPv4+IPv6 has to be explicitly implemented.
"But it works sometimes". This happens when VPN connections are not reliable. It leads to all sorts of solutions that are mere coincidences.
What exactly is happening:
HttpClient.GetAsync() uses default DNS resolution and can connect using both IPv4 and IPv6 addresses. It does not discriminate and there is no direct way to influence protocol selection. If DNS returns inaccessible address then HttpClient may use that invalid address to connect resulting in timeout.
Possible workarounds:
The best: ask IT to fix IPv6 DNS issues. DNS should not report inaccessible addresses.
Good: implement Happy eyeballs approach. Connect to both IPv6 and IPv4 host addresses using numeric IP instead of automatic resolution using host name.
OK: Always connect to IPv4 using numeric IP.
Here is the piece of code that shows how to connect to a specific IP address:
// Get DNS entries for the host.
var hostEntry = Dns.GetHostEntry(uri.Host);
// Get IPv4 address
var ip4 = hostEntry.AddressList.First(addr => addr.AddressFamily == AddressFamily.InterNetwork);
// Build URI with numeric IPv4
var uriBuilderIP4 = new UriBuilder(uri);
uriBuilderIP4.Host = ip4.ToString());
var uri4 = uriBuilder4.Uri;
// Get IPv6 address
var ip6 = hostEntry.AddressList.First(addr => addr.AddressFamily == AddressFamily.InterNetworkV6);
// Build URI with numeric IPv6
var uriBuilderIP6 = new UriBuilder(uri);
uriBuilderIP6.Host = $"[{ip6}]";
var uri6 = uriBuilder6.Uri;
For HTTPS connections numeric addresses work only with "host" header with the name of the host (not an IP address) in it. Here is the way to add it.
var client = new HttpClient();
// Add "host" header with real host name e.g. stackoverflow.com
client.DefaultRequestHeaders.Add("Host", uri.Host);
Got an asp.net web page in c#. One thing we would like to do is track hits to the site including their IP address. I implemented some code (thanks to SO) but the logged IP address always seem to be local, ie: 192.168.x.x. I have tried it from a variety of devices, even my phone and Version MiFi just to make sure its not something weird with the ISP but the log always list the same 2-3 different internal ip addresses (seems to change a little as the day goes on).
Here is my function that gets the IP (again thanks to postings here on SO):
protected IPAddress GetIp(HttpRequest request)
{
string ipString;
if (string.IsNullOrEmpty(request.ServerVariables["HTTP_X_FORWARDED_FOR"]))
ipString = request.ServerVariables["REMOTE_ADDR"];
else
ipString = request.ServerVariables["HTTP_X_FORWARDED_FOR"].Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
IPAddress result;
if (!IPAddress.TryParse(ipString, out result))
result = IPAddress.None;
return result;
}
public void logHit()
{
IPAddress ip = GetIp(Request);
string sIP = ip.ToString();
}
I tried this as well which yields the same result:
HttpContext.Current.Request.UserHostAddress;
When I do a call on the client side using something like the service on appspot, it works just fine:
<script type="application/javascript">
function getip(json) {
//txtIP is a input box on the form
document.getElementById("txtIP").value = json.ip;
}
</script>
<script type="application/javascript" src="http://jsonip.appspot.com/?callback=getip"></script>
I suppose I could do a round-about way by hitting that appspot link and parse it out but that seems like a whole lot of trouble for something that should be simple.
Could it be the IIS on the server? Some kind of redirect going on? The ip addresses logged are NOT the servers. The problem is I dont have direct access to it so I have to talk to the guys that admin it and would like to give them some direction before they just start changing things.
Thanks
Ernie
If the HTTP_X_FORWARDED_FOR header is truly supported, then I think this would not be either forward or reverse proxy server causing this, but more likely Dynamic Network Address Translation or Dynamic Port Address Translation, which is happening below the application layer on the TCP/IP stack and thus would not affect an HTTP request header.
There are many ways to configure NAT, most of which would not cause these symptoms, but it is certainly possible to configure NAT in a way that would present this problem. Dynamic NAT or Dynamic PAT would be two such examples, and I would suggest this is what you ask your network administrators.
For more on Dynamic NAT/PAT, with good examples, you could review: http://www.cisco.com/en/US/docs/security/asa/asa82/configuration/guide/nat_dynamic.html
In a typical NAT scenario, the request packets reach the NAT device (firewall or router) as:
FROM - 5.5.5.5 (public address of the client)
TO - 6.6.6.6 (the public address of the server)
The "typical" NAT configuration would rewrite only the destination, as follows:
FROM - 5.5.5.5
TO - 192.168.6.6 (the private address of the server)
In this typical case, the server would still see REMOTE_ADDR as 5.5.5.5, as that is the source address on the incoming request. Then, the packets would be returned to 5.5.5.5, and the response would return to the client successfully.
Now, in the case of dynamic PAT, for example, the request would reach the NAT device as follows:
FROM - 5.5.5.5
TO - 6.6.6.6
Then, the NAT device would rewrite both source and destination packets, maintaining this "dynamic" mapping for only the lifetime of the request:
FROM - 192.168.1.1:12345 (the dynamic PAT address)
TO - 192.168.6.6 (the private address of the server)
Now, when the server sees this request, it appears to be from private address 192.168.1.1. In fact, with a strict PAT all requests will appear to be from this address. In your case, there are 2 or 3 of these addresses, probably because you may have enough traffic that you risk running out of ports if you use only a single dynamic PAT address.
So, your REMOTE_ADDR is 192.168.1.1, because that is actually the source address on the request packets. There is no HTTP_X_FORWARDED_FOR, because the Dynamic PAT is occurring at a lower TCP/IP layer (address and not application).
Finally, the response is sent back to 192.168.1.1:12345, which routs to the NAT device, which for the duration of the request/response (see the Cisco documentation above) maps it back to 5.5.5.5, and then drops the "dynamic" mapping.
Everything worked perfectly, the client gets the response back, except that you have no idea of the actual client address from the viewpoint of the server. And if it is dynamic NAT in play, I don't see how you could get this information from the server.
Fortunately, you did exactly the right thing to get the information in javascript on the client, so this likely solves your problem as well as it could be solved.
It depends on your network structure. Simply a firewall or load balancer can change the variables which you are checking.
if you are using a load balancer check this:
How to get visitor IP on load balancing machine using asp.net
if your sever is behind a firewall check this:
Find if request was forwarded from firewall to IIS
I am a student in my fourth year in university. My graduation project is a download manager which i intend to code with C#.
when checked the MSDN documentation the project looked easy. But the problem is that my teacher wants me to incorporate multihoming to the project. He want the download manager to:
split the file the user wants to download to multiple segments.
for each segment the DM should create a connection and request that segment from the server.
after all segments finish downloading the DM should combine the segments into one file.
If multihoming exists each connection should go(or route) thru different ISP (as when multihoming is used, the computer is connected to more than one ISP thru more than one network adapter) as this process should accelerate the download of the file.
I can accomplish the first three steps but I couldn't find a solution to the fourth step so can anyone pleas help me or guide me thru the right way.
I am not an experienced networking and protocol programer I have only choose C# because it simplify the process of sending and requesting files.
I believe that your answer lies with the ServicePoint.BindIPEndPointDelegate property, which you can set within your HttpWebRequest instance. Quoting MSDN:
Some load balancing techniques require a client to use a specific
local IP address and port number, rather than IPAddress.Any (or
IPAddress.IPv6Any for Internet Protocol Version 6) and an ephemeral
port. Your BindIPEndPointDelegate can satisfy this requirement.
Basically, BindIPEndPointDelegate lets you select the local endpoint to use for your connection. You can retrieve the list of all local IP addresses using Dns.GetHostAddresses(Dns.GetHostName()), and then pick one at random within the delegate. You do, however, need to be careful to match the address family: If the remote endpoint is IPv6, you need to select a local IPv6 address.
I’m including some sample code below.
Uri uri = new Uri("http://google.com");
Random random = new Random();
IPAddress[] localAddresses = Dns.GetHostAddresses(Dns.GetHostName());
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
webRequest.ServicePoint.BindIPEndPointDelegate =
(servicePoint, remoteEndPoint, retryCount) =>
{
var allowedLocalAddresses =
localAddresses.Where(localAddress =>
localAddress.AddressFamily == remoteEndPoint.AddressFamily).ToArray();
IPAddress selectedLocalAddress =
allowedLocalAddresses[random.Next(allowedLocalAddresses.Length)];
return new IPEndPoint(selectedLocalAddress, 0);
};
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
References:
How to change originating IP in HttpWebRequest
Choosing which IP the HTTP request is using when having multiple IPs (.NET)
Edit: I am not suggesting that you should actually pick local addresses at random for your project; the above code was just the simplest demonstration I could think of. If you’re establishing a number of concurrent connections and want to maximize load-balancing across all available adapters, then you should cycle through your local addresses; this would ensure that all adapters are handling an approximately equal number of connections each.
We have a written a C# application that communicates with any one of a group of IP in the cloud.
Any one of which may not be working. We use the URL of the address as the IIS server is expecting a Host Header Name in order to route to the correct application interface.
So we set the Hosts file to point the URL at an IP.
We then send a command at the URL to get back the server time.
This tells us the connection is working.
If we don't get a response we assume the connection is dead. We then write a new IP from a list into the Hosts file and we try again.
This is where we hit a bug. The application doesn't seem to see the Hosts file has changed and uses the old (bad) IP.
There is no caching built into the application so we are assuming that Windows is caching for us.
We've tried to flush caches with:
ipconfig /flushdns
arp -d *
nbtstat -R
We still get the same problem.
Any thoughts on how to clear the cache?
If you can't address this at the server end (e.g. a load balancer, etc), then just use the IP address list in your code:
var req = HttpWebRequest.Create("http://" + IPAdd.ToString() + "/path_to_query_time");
((HttpWebRequest)req).Host = "yourhostheaderhere";
var resp = req.GetResponse();
//If things have gone wrong here, change IPAdd to the next IP address and start over.
Don't go messing with the users settings to try and solve a problem in your application that's of your own making.
My GPRS modem has got a sim card. it can connect Web. Web service give it a ip number. i need it. like that: http://www.your-ip-address.com/
How can i do that C#?
You can use the static method WebClient.DownloadString(url) to read your external IP address from any web service providing such data:
string ip = System.Net.WebClient.DownloadString("http://whatismyip.org/");
If you are going to use this in a production environment, better make sure that the URL you are pointing to, is guaranteed to stay around for the entire lifespan of your application. The best way is probably to host the web service yourself.
Also, you should add some error checking around this code, as it will fail if the internet connection or the web service is unavailable.
You can get a list of your IP addresses via DNS using the following code:
var name = Dns.GetHostName();
var entry = Dns.GetHostEntry(name);
foreach (var address in entry.AddressList) {
Console.WriteLine(address);
}
If you want the IP address as a property of the hardware, you can use the System.Management.ManagementClass with the name Win32_NetworkAdapterConfiguration. See http://msdn.microsoft.com/en-us/library/system.management.managementclass.aspx for details.
You can create a WebRequest to http://whatismyip.com/automation/n09230945.asp which houses only your IP address
Start here