系統出現大量HTTP Auto Proxy Detection Worker Process
轉載請註明文章出處: https://tlanyan.me/many-http-auto-proxy-detection-worker-processes
今天開啟工作管理員,發現有大量“HTTP Auto Proxy Detection Worker Process”程序,畫風如下:
根據程序名稱,應該和代理有關,因為電腦上開著Shadowsocks。但是這麼多什麼鬼?打群架嗎?
退出SS程式,發現這些程序不會隨之退出。意識到這超出了我的知識範圍,於是馬上開啟Google學學。根據有限的搜尋結果,基本上確認 和SS有關 ,並且 僅會出現在1809版的Windows 10上 。我今天才發現這個現象,順便確認了系統是1809版的bug10:
花了一個多小時理解WPAD、PAC和pacjsworker.exe關係,並加上自己反覆測驗,得到一些結論:
- HTTP Auto Proxy Detection Worker Process程序的程式檔案是”C:\Windows\System32\pacjsworker.exe”,由WPAD服務啟動;
- 這些程序不能手工殺死,重啟系統才能解決,使用者退出(logout)再登入也不行;
- WPAD服務(Win HTTP Web Proxy Auto Discovery Service)的屬性不能修改,通過重啟WPAD服務殺死程序的路也不通;
- 1809版本才會出現,在這之前版本的系統上執行正常;根據Twitter連結 https://twitter.com/epakskape/status/1007316208087994368 ,應該是build 17692引入新功能導致;
- 情況復現:開啟SS客戶端,選擇PAC模式,勾選啟用系統代理;然後按電源鍵(或其他方式)讓電腦進入休眠;接著喚醒電腦進入桌面,工作管理員中就多了一個HTTP Auto Proxy Detection Worker Process程序;如此反覆進入休眠又啟動,每次都會出現一個新程序;
- 後來發現不需要休眠也能復現情況:開啟SS客戶端,選擇PAC模式,開啟工作管理員;然後不斷禁用/啟用系統代理,在工作管理員視窗中可實時看到每次啟用系統代理後都會多一個程序;
- 最新版的SS客戶端依然有這個問題;
- 每次SS啟動系統代理後的PAC地址均不同;
- PAC地址中的secret引數僅在勾選“保護本地PAC(secure local PAC)”選項時才會出現,但t引數一直都在。
根據網上知識,加上個人實驗和思考,對問題原因的理解為:WPAD是系統關鍵服務,使用者不能更改;以PAC模式啟動SS時,SS會在LAN配置中設定一個新的PAC指令碼地址;WPAD檢測到有新的PAC指令碼地址,喚醒一個新的pacjsworker.exe程序監聽該地址;PAC地址失效後,監聽程序不退出,於是程序堆積,慢慢出現幾十上百個程序的壯觀場景。
總結問題根源:1. Windows 10的程序不自動退出;2. 每次從休眠過來後,SS客戶端生成不同的PAC地址並將其配置到LAN設定中。
把問題搞清楚了,解決方案基本上章口就萊:
- 使用全域性模式;全域性模式不會設定PAC配置指令碼,WPAD服務也就不會拉起新的程序;
- 等待巨硬修復問題;去年下半年就爆出問題,到現在問題依舊,應該有得等(本人最近才更新1809版本,故而發現得遲);另外我不認為這是巨硬的鍋,他們未必會修復;
- 重新編譯SS客戶端,生成相同的PAC(至少未重啟SS客戶端前PAC地址應一致)。
我的解決方案是重新編譯SS客戶端,根據 @Joelism 的提示及自己理解,做了兩個方案的客戶端:
-
方案一:總是生成相同的PAC地址,除非人工編輯”pac-secret.txt”檔案。改動程式碼如下:
// 檔案: shadowsocks-csharp\Controller\Service\PACServer.cs public void UpdateConfiguration(Configuration config) { this._config = config; if (config.secureLocalPac) { // 註釋掉部分 // var rd = new byte[32]; // RNG.GetBytes(rd); // PacSecret = $"&secret={Convert.ToBase64String(rd)}"; if (!File.Exists(PAC_SECRET_FILE)) { var rd = new byte[32]; RNG.GetBytes(rd); string secret = Convert.ToBase64String(rd); PacSecret = $"secret={secret}"; File.WriteAllText(PAC_SECRET_FILE, secret); } else { PacSecret = $"secret={File.ReadAllText(PAC_SECRET_FILE)}"; } } else { PacSecret = ""; } // 註釋掉部分 // PacUrl = $"http://127.0.0.1:{config.localPort}/pac?t={GetTimestamp(DateTime.Now)}{PacSecret}"; PacUrl = $"http://127.0.0.1:{config.localPort}/pac?{PacSecret}"; }
這個方案保證不管系統休眠重啟,還是退出SS客戶端再開啟,都只會有一個HTTP Auto Proxy Detection Worker Process程序。
-
僅當系統中無PAC程序執行時才生成新的PAC地址並設定到LAN中。程式碼如下:
// 檔案: shadowsocks-csharp\Controller\ShadowsocksController.cs protected void Reload() { Encryption.RNG.Reload(); // some logic in configuration updated the config when saving, we need to read it again _config = Configuration.Load(); StatisticsConfiguration = StatisticsStrategyConfiguration.Load(); if (privoxyRunner == null) { privoxyRunner = new PrivoxyRunner(); } if (_pacServer == null) { _pacServer = new PACServer(); _pacServer.PACFileChanged += pacServer_PACFileChanged; _pacServer.UserRuleFileChanged += pacServer_UserRuleFileChanged; // 這一行程式碼從外部移入 _pacServer.UpdateConfiguration(_config); } // 每次喚醒都更新的程式碼刪除 // _pacServer.UpdateConfiguration(_config); if (gfwListUpdater == null) { gfwListUpdater = new GFWListUpdater(); gfwListUpdater.UpdateCompleted += pacServer_PACUpdateCompleted; gfwListUpdater.Error += pacServer_PACUpdateError; }
這個方案保證不退出SS客戶端情況下只有一個pacjsworker.exe程序。缺點是如果頻繁退出並重啟SS客戶端,同樣會出現有大量程序的現象。
根據原始碼思路,我認為第二種方案更合理,是原作者想要的。當然你應該想得到,我是先根據網上提示實現方案一,測試達到效果後繼續思考才做出的方案二。從這個角度也是方案二更合理。
兩個方案的exe檔案我都編譯好了,需要請自取: 方案一 方案二
稍後我會發一個pull request到官方庫,使用方案二修復該問題。