/// <summary> /// Removes all gamespy related redirects in the specified hosts file container /// </summary> /// <param name="HostFile"></param> private static void RemoveRedirects(HostsFile HostFile) { // Remove Gamespy Addresses. Use a Bitwise OR here to execute both methods if (HostFile.Remove(Bf2StatsHost) | HostFile.RemoveAll(GamespyHosts)) { // Save Changes HostFile.Save(); // Flush the Cache of the gamespy hosts foreach (string host in GamespyHosts) { DnsFlushResolverCacheEntry(host); } // Flush stats server DnsFlushResolverCacheEntry(Bf2StatsHost); } }
/// <summary> /// Preforms the pings required to fill the dns cache. /// The reason we ping, is because once the HOSTS file is locked, any request /// made to a url (when the DNS cache is empty), will skip the hosts file, because /// it cant be read. If we ping first, then the DNS cache fills up with the IP /// addresses in the hosts file. /// </summary> public static void RebuildDNSCache(CancellationToken CancelToken) { // Must be hosts file! if (RedirectMethod == RedirectMode.DnsServer || !RedirectsEnabled) { return; } // Grab hosts file base HostsFile hFile = (RedirectMethod == RedirectMode.HostsFile) ? HostsFileSys as HostsFile : HostsFileIcs as HostsFile; // Rebuild the DNS cache with the hosts file redirects foreach (string hostname in hFile.GetLines().Keys) { // Quit on cancel if (CancelToken.IsCancellationRequested) { return; } // Only ping gamespy urls with the hosts ics file if (RedirectMethod == RedirectMode.HostsIcsFile && !hostname.Contains("gamespy")) { continue; } // Attempt to ping the server try { // Clear the record from the DNS cache DnsFlushResolverCacheEntry(hostname); // Ping server to get the IP address in the dns cache Dns.GetHostAddresses(hostname); } catch { continue; } } }
/// <summary> /// Queries the DNS Cache for the Gamespy hosts, and verifies that the /// IP addresses in the DNS Cache match that of the desired redirect IP /// </summary> public static bool VerifyDNSCache(IProgress <DnsCacheResult> Progress = null) { // Nothing to do here if redirects are disabled if (!RedirectsEnabled) { return(false); } // Grab our saved hosts file IP addresses if (RedirectMethod != RedirectMode.DnsServer) { // Grab hosts file base HostsFile hFile = (RedirectMethod == RedirectMode.HostsFile) ? HostsFileSys as HostsFile : HostsFileIcs as HostsFile; // Fetch our saved IPAddresses GamespyServerAddress = (hFile.HasEntry("master.gamespy.com")) ? hFile.Get("master.gamespy.com") : null; StatsServerAddress = (hFile.HasEntry(Bf2StatsHost)) ? hFile.Get(Bf2StatsHost) : null; } // Flush our cache report DnsCacheReport.Entries.Clear(); // Verify Gamespy Server IP addresses if (GamespyServerAddress != null) { foreach (string address in GamespyHosts) { // Create new report DnsCacheResult Result = new DnsCacheResult(address, GamespyServerAddress); // Add the result to the report DnsCacheReport.AddOrUpdate(Result); // Report progress if we have a progress object if (Progress != null) { Progress.Report(Result); } } } // Verify Stats Server address if (StatsServerAddress != null) { // Create new report DnsCacheResult Result = new DnsCacheResult(Bf2StatsHost, StatsServerAddress); // Add the result to the report DnsCacheReport.AddOrUpdate(Result); // Report progress if we have a progress object if (Progress != null) { Progress.Report(Result); } } // Set internal DnsCacheReport.LastRefresh = DateTime.Now; return(DnsCacheReport.ErrorFree); }
/// <summary> /// Applies the specified IP address redirects for the chosen redirect method /// </summary> public static Task <bool> ApplyRedirectsAsync(IProgress <TaskStep> Progress) { return(Task.Run(() => { // Remove old settings if (RedirectsEnabled) { RemoveRedirects(); } // Invalid on no IP addresses if (StatsServerAddress == null && GamespyServerAddress == null) { return false; } // Set new desired addresses if (StatsServerAddress != null) { Program.Config.LastStatsServerAddress = StatsServerAddress.ToString(); } if (GamespyServerAddress != null) { Program.Config.LastLoginServerAddress = GamespyServerAddress.ToString(); } Program.Config.Save(); // Can't do anything with a dns server if (RedirectMethod == RedirectMode.DnsServer) { return true; } // === Apply new settings === // // Grab hosts file base HostsFile hFile = (RedirectMethod == RedirectMode.HostsFile) ? HostsFileSys as HostsFile : HostsFileIcs as HostsFile; // Unlock system hosts file if (RedirectMethod == RedirectMode.HostsFile) { // Make sure file is writable if (SysHostsFile.IsLocked && !HostsFileSys.UnLock()) { Progress.Report(new TaskStep(0, "Cannot allow READ permissions on the Hosts File", true, hFile.LastException)); return false; } else { Progress.Report(new TaskStep(0, "")); } } // Make sure file is writable if (!hFile.CanRead) { Progress.Report(new TaskStep(1, "Cannot read the Hosts File", true, hFile.LastException)); return false; } else { Progress.Report(new TaskStep(1, "")); } // Make sure file is readable if (!hFile.CanWrite) { Progress.Report(new TaskStep(2, "Cannot write to the Hosts File", true, hFile.LastException)); return false; } else { Progress.Report(new TaskStep(2, "")); } // ===== Set Redirect Addresses ===== // // Stats Server if (StatsServerAddress != null) { hFile.Set(Bf2StatsHost, StatsServerAddress); } // Gamespy Servers if (GamespyServerAddress != null) { foreach (string hostname in GamespyHosts) { hFile.Set(hostname, GamespyServerAddress); } } // Report Progress Progress.Report(new TaskStep(3, "Gamespy Redirects Set")); // ===== Save Redirects ===== // int Step = 4; string ErrDesc = ""; try { // Attempt to save the hosts file ErrDesc = "Unable to Save Hosts File!"; hFile.Save(); // Report Success Progress.Report(new TaskStep(Step++, "Hosts File Saved Successfully")); // Rebuild the DNS Cache ErrDesc = "Failed to Rebuild the DNS Cache"; RebuildDNSCache(CancellationToken.None); // Report Success Progress.Report(new TaskStep(Step++, "DNS Cache Rebuilt Successfully")); } catch (Exception e) { RemoveRedirects(); Progress.Report(new TaskStep(Step, ErrDesc, true, e)); return false; } // Lock system hosts File if (RedirectMethod == RedirectMode.HostsFile) { if (!Program.Config.LockHostsFile) { // Report Success Progress.Report(new TaskStep(Step++, "")); return true; } else if (HostsFileSys.Lock()) { // Report Success Progress.Report(new TaskStep(Step++, "Hosts File Read Permissions Removed")); return true; } else { // Report Error Progress.Report(new TaskStep(Step++, "Cannot Remove Hosts File Read Permissions!", true, HostsFileSys.LastException)); return true; } } return true; })); }
/// <summary> /// The main entry point for the redirector /// </summary> /// <returns>Returns wether the DNS cache results match the selected IPAddresses</returns> public static Task <bool> Initialize() { return(Task.Run <bool>(() => { // Only initialize once if (!IsInitialized) { IsInitialized = true; // Set the System.Net DNS Cache refresh timeout to 1 millisecond ServicePointManager.DnsRefreshTimeout = 1; // Get config options RedirectMethod = Program.Config.RedirectMode; // Create new Instances HostsFileSys = new SysHostsFile(); HostsFileIcs = new HostsFileIcs(); // Detect redirects bool IcsHasRedirects = HostsFileIcs.HasAnyEntry(GamespyHosts) || HostsFileIcs.HasEntry(Bf2StatsHost); bool HostsHasRedirects = HostsFileSys.HasAnyEntry(GamespyHosts) || HostsFileSys.HasEntry(Bf2StatsHost); // Both files cannot have redirects! if (IcsHasRedirects && HostsHasRedirects) { try { // Remove all redirects RemoveRedirects(HostsFileIcs); RemoveRedirects(HostsFileSys); } catch { } } else if (IcsHasRedirects || HostsHasRedirects) { // Do the settings match? bool match = (RedirectMethod == RedirectMode.HostsFile && HostsHasRedirects) || (RedirectMethod == RedirectMode.HostsIcsFile && IcsHasRedirects); // Perform switch if the settings don't match if (!match) { RedirectMethod = (RedirectMethod == RedirectMode.HostsFile) ? RedirectMode.HostsIcsFile : RedirectMode.HostsFile; } // === Fetch our redirect data // Grab hosts file base HostsFile hFile = (RedirectMethod == RedirectMode.HostsFile) ? HostsFileSys as HostsFile : HostsFileIcs as HostsFile; // Parse Stats Address if (hFile.HasEntry("bf2web.gamespy.com")) { StatsServerAddress = hFile.Get("bf2web.gamespy.com"); } // Parse Gamespy Address if (hFile.HasEntry("master.gamespy.com")) { GamespyServerAddress = hFile.Get("master.gamespy.com"); } // Lock hosts file if (RedirectMethod == RedirectMode.HostsFile && Program.Config.LockHostsFile) { HostsFileSys.Lock(); } } else if (RedirectMethod == RedirectMode.DnsServer) { IPAddress addy; // Parse last used Stats Server Address if (Networking.TryGetIpAddress(Program.Config.LastStatsServerAddress, out addy)) { StatsServerAddress = addy; } // Parse gamespy saved address if (Networking.TryGetIpAddress(Program.Config.LastLoginServerAddress, out addy)) { GamespyServerAddress = addy; } } } // Verify cache return (RedirectsEnabled) ? VerifyDNSCache() : true; })); }
/// <summary> /// Removes all gamespy related redirects in the specified hosts file container /// </summary> /// <param name="HostFile"></param> private static void RemoveRedirects(HostsFile HostFile) { // Remove Gamespy Addresses. Use a Bitwise OR here to execute both methods if (HostFile.Remove(Bf2StatsHost) | HostFile.RemoveAll(GamespyHosts)) { // Save Changes HostFile.Save(); // Flush the Cache of the gamespy hosts foreach (string host in GamespyHosts) DnsFlushResolverCacheEntry(host); // Flush stats server DnsFlushResolverCacheEntry(Bf2StatsHost); } }