You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

GfwListUpdater.cs 4.6 kB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Net;
  5. using System.Text;
  6. using Newtonsoft.Json;
  7. using Shadowsocks.Model;
  8. using Shadowsocks.Properties;
  9. using Shadowsocks.Util;
  10. namespace Shadowsocks.Controller
  11. {
  12. public class GFWListUpdater
  13. {
  14. private const string GFWLIST_URL = "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt";
  15. public event EventHandler<ResultEventArgs> UpdateCompleted;
  16. public event ErrorEventHandler Error;
  17. public class ResultEventArgs : EventArgs
  18. {
  19. public bool Success;
  20. public ResultEventArgs(bool success)
  21. {
  22. this.Success = success;
  23. }
  24. }
  25. private static readonly IEnumerable<char> IgnoredLineBegins = new[] { '!', '[' };
  26. private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
  27. {
  28. try
  29. {
  30. File.WriteAllText(Utils.GetTempPath("gfwlist.txt"), e.Result, Encoding.UTF8);
  31. bool pacFileChanged = MergeAndWritePACFile(e.Result);
  32. UpdateCompleted?.Invoke(this, new ResultEventArgs(pacFileChanged));
  33. }
  34. catch (Exception ex)
  35. {
  36. Error?.Invoke(this, new ErrorEventArgs(ex));
  37. }
  38. }
  39. public static bool MergeAndWritePACFile(string gfwListResult)
  40. {
  41. string abpContent = MergePACFile(gfwListResult);
  42. if (File.Exists(PACDaemon.PAC_FILE))
  43. {
  44. string original = FileManager.NonExclusiveReadAllText(PACDaemon.PAC_FILE, Encoding.UTF8);
  45. if (original == abpContent)
  46. {
  47. return false;
  48. }
  49. }
  50. File.WriteAllText(PACDaemon.PAC_FILE, abpContent, Encoding.UTF8);
  51. return true;
  52. }
  53. private static string MergePACFile(string gfwListResult)
  54. {
  55. string abpContent;
  56. if (File.Exists(PACDaemon.USER_ABP_FILE))
  57. {
  58. abpContent = FileManager.NonExclusiveReadAllText(PACDaemon.USER_ABP_FILE, Encoding.UTF8);
  59. }
  60. else
  61. {
  62. abpContent = Resources.abp_js;
  63. }
  64. List<string> userruleLines = new List<string>();
  65. if (File.Exists(PACDaemon.USER_RULE_FILE))
  66. {
  67. string userrulesString = FileManager.NonExclusiveReadAllText(PACDaemon.USER_RULE_FILE, Encoding.UTF8);
  68. userruleLines = ParseToValidList(userrulesString);
  69. }
  70. List<string> gfwLines = new List<string>();
  71. gfwLines = ParseBase64ToValidList(gfwListResult);
  72. abpContent = abpContent.Replace("__USERRULES__", JsonConvert.SerializeObject(userruleLines, Formatting.Indented))
  73. .Replace("__RULES__", JsonConvert.SerializeObject(gfwLines, Formatting.Indented));
  74. return abpContent;
  75. }
  76. public void UpdatePACFromGFWList(Configuration config)
  77. {
  78. Logging.Info($"Checking GFWList from {GFWLIST_URL}");
  79. WebClient http = new WebClient();
  80. if (config.enabled)
  81. {
  82. http.Proxy = new WebProxy(
  83. config.isIPv6Enabled
  84. ? $"http://[{IPAddress.IPv6Loopback.ToString()}]"
  85. : $"http://{IPAddress.Loopback.ToString()}",
  86. config.localPort);
  87. }
  88. http.DownloadStringCompleted += http_DownloadStringCompleted;
  89. http.DownloadStringAsync(new Uri(GFWLIST_URL));
  90. }
  91. public static List<string> ParseBase64ToValidList(string response)
  92. {
  93. byte[] bytes = Convert.FromBase64String(response);
  94. string content = Encoding.ASCII.GetString(bytes);
  95. return ParseToValidList(content);
  96. }
  97. private static List<string> ParseToValidList(string content)
  98. {
  99. List<string> valid_lines = new List<string>();
  100. using (var sr = new StringReader(content))
  101. {
  102. foreach (var line in sr.NonWhiteSpaceLines())
  103. {
  104. if (line.BeginWithAny(IgnoredLineBegins))
  105. continue;
  106. valid_lines.Add(line);
  107. }
  108. }
  109. return valid_lines;
  110. }
  111. }
  112. }