Skip to content
Permalink
Browse files

Make DNS lookup threadsafe, also still work if IPv4 resolution fails

  • Loading branch information...
UnknownShadow200 committed May 31, 2017
1 parent f7ed37d commit 2279f1394be0cce4f225c1df67b7ad0ba781b306
Showing with 39 additions and 36 deletions.
  1. +39 −36 fCraft/Network/HttpUtil.cs
@@ -1,53 +1,53 @@
// Part of fCraft | Copyright 2009-2015 Matvei Stefarov <me@matvei.org> | BSD-3 | See LICENSE.txt //Copyright (c) 2011-2013 Jon Baker, Glenn Marien and Lao Tszy <Jonty800@gmail.com> //Copyright (c) <2012-2014> <LeChosenOne, DingusBungus> | ProCraft Copyright 2014-2016 Joseph Beauvais <123DMWM@gmail.com>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using JetBrains.Annotations;

namespace fCraft
{
namespace fCraft {
/// <summary> Static class for assisting with making web requests. </summary>
public static class HttpUtil
{
public static class HttpUtil {
// Dns lookup, to make sure that IPv4 is preferred for connections
static readonly Dictionary<string, IPAddress> TargetAddresses = new Dictionary<string, IPAddress>();
static readonly Dictionary<string, IPAddress> cache = new Dictionary<string, IPAddress>();
static DateTime nextDnsLookup = DateTime.MinValue;
static readonly TimeSpan DnsRefreshInterval = TimeSpan.FromMinutes(30);
static readonly object dnsLock = new object();

static IPAddress RefreshTargetAddress([NotNull] Uri requestUri)
{
if (requestUri == null) throw new ArgumentNullException("requestUri");

string hostName = requestUri.Host.ToLowerInvariant();
IPAddress targetAddress;
if (!TargetAddresses.TryGetValue(hostName, out targetAddress) || DateTime.UtcNow >= nextDnsLookup) {
IPAddress[] allAddresses = null;
static IPAddress LookupIPv4([NotNull] Uri uri) {
if (uri == null) throw new ArgumentNullException("requestUri");
string hostName = uri.Host.ToLowerInvariant();
IPAddress ip;

lock (dnsLock) {
if (cache.TryGetValue(hostName, out ip) && DateTime.UtcNow < nextDnsLookup) return ip;
}

try {
// Perform a DNS lookup on given host. Throws SocketException if no host found.
IPAddress[] allIPs = null;
try {
// Perform a DNS lookup on given host. Throws SocketException if no host found.
try {
allAddresses = Dns.GetHostAddresses(requestUri.Host);
} catch {
return null;
}
// Find a suitable IPv4 address. Throws InvalidOperationException if none found.
targetAddress = allAddresses.First(ip => ip.AddressFamily == AddressFamily.InterNetwork);
} catch (SocketException ex) {
Logger.Log(LogType.Error,
"HttpUtil.RefreshTargetAddress: Error looking up server URL: {0}", ex);
} catch (InvalidOperationException) {
Logger.Log(LogType.Warning, "HttpUtil.RefreshTargetAddress: {0} does not have an IPv4 address!",
requestUri.Host);
} catch (UriFormatException) {
Logger.Log(LogType.Warning, "Invalid URI: The hostname could not be parsed.");

allIPs = Dns.GetHostAddresses(uri.Host);
} catch {
return null;
}
TargetAddresses[hostName] = targetAddress;
nextDnsLookup = DateTime.UtcNow + DnsRefreshInterval;

// Find a suitable IPv4 address. Throws InvalidOperationException if none found.
ip = allIPs.First(address => address.AddressFamily == AddressFamily.InterNetwork);
} catch (SocketException ex) {
Logger.Log(LogType.Error, "HttpUtil.LookupIPv4: Error looking up server URL: {0}", ex);
} catch (InvalidOperationException) {
Logger.Log(LogType.Warning, "HttpUtil.LookupIPv4: {0} does not have an IPv4 address!", uri.Host);
} catch (UriFormatException) {
Logger.Log(LogType.Warning, "Invalid URI: The hostname could not be parsed.");

}
return targetAddress;

lock (dnsLock) { cache[hostName] = ip; }
nextDnsLookup = DateTime.UtcNow + DnsRefreshInterval;
return ip;
}


@@ -61,9 +61,12 @@ static IPAddress RefreshTargetAddress([NotNull] Uri requestUri)
req.ServicePoint.BindIPEndPointDelegate = Server.BindIPEndPointCallback;
req.Timeout = (int)timeout.TotalMilliseconds;
req.UserAgent = Updater.UserAgent;

if (uri.Scheme == "http") {
req.Proxy = new WebProxy("http://" + RefreshTargetAddress(uri) + ":" + uri.Port);
IPAddress ipv4 = LookupIPv4(uri);
if (ipv4 != null) {
req.Proxy = new WebProxy("http://" + LookupIPv4(uri) + ":" + uri.Port);
}
}
return req;
}

0 comments on commit 2279f13

Please sign in to comment.
You can’t perform that action at this time.