dsh-proxy-switch: Enable DSH's web_fetch to fetch web pages normally in a proxy environment

Preface

DSH’s web_fetch works fine in a direct connection environment, but once software like Clash, Surge, or v2rayN is running, fetching often fails. Troubleshooting usually points to two types of issues: TUN mode resolves domains to fake addresses like 198.18.x.x, and direct connection security checks reject them; or only “System Proxy” is enabled without TUN, DSH doesn’t read the system proxy, and websites requiring a proxy won’t open. Hardcoding HTTP_PROXY into ~/.dsh/.env does connect, but once the proxy is turned off, the model conversation also breaks. Below is an introduction to dsh-proxy-switch, a plugin written specifically for this scenario.

What is it

  • Maintainer: lightrivers
  • Package name: @lightrivers/dsh-proxy-switch, version 0.4.4, license MIT
  • GitHub: https://github.com/lightrivers/dsh-proxy-switch
  • Directory page: https://www.skillhub.cn/plugins/lightrivers/dsh-proxy-switch, category “Network Tools”, starred 0

One-sentence positioning: Automatically detects the local HTTP proxy; when the proxy is on, web_fetch goes through the proxy, and after the proxy is turned off, it automatically switches back to direct connection, providing a switchable line for web_fetch. The default scope is “web_fetch only”, does not modify global network settings, process environment variables, or subprocess environments, so model conversations and other tools are not affected.

What problems does it solve

Applicable situations listed in README:

  • web_fetch reports non-public IP address, or domain is resolved to 198.18.x.x
  • Proxy has TUN / Enhanced Mode / Fake-IP enabled, web_fetch fails
  • Only System Proxy is enabled, TUN is not, DSH cannot read the system proxy, websites requiring a proxy cannot be opened
  • After hardcoding HTTP_PROXY, once the proxy is off, even model conversations are disconnected
  • Need to manually change configuration every time the proxy is toggled

The reason is that TUN mode resolves domains to fake addresses in the 198.18.0.0/15 segment; the web_fetch security check does not allow accessing internal network addresses when connecting directly. And once the proxy address is hardcoded, nothing can connect when the proxy is closed. The plugin provides a switchable line for web_fetch outside of these two paths.

It should be noted that the README explicitly states: Starting from DeepSeek Harness 0.2.2, web_fetch no longer rejects fake-IP and internal network addresses, so if only TUN is used, the new version can scrape web pages without installing the plugin. The plugin is still suitable for users who only enable system proxy or need to automatically switch based on proxy on/off; additionally, the plugin still only allows public network addresses during direct connection, which can block access to the local machine and internal network services.

Environment requirements

Item Requirement
DeepSeek Harness Desktop 0.2.1, 0.2.2 (0.2.2-rc.1 tested)
System macOS (fully verified); Windows, Linux (code supported, not fully verified on real machines)
Proxy Local HTTP proxy or “Mixed Port” (Clash / mihomo / Clash Verge, Surge, v2rayN, etc.), SOCKS, PAC not supported

Core features

  1. Automatic proxy detection. Prioritizes reading system proxy settings (macOS Network Settings, Windows Internet Options, Linux GNOME/KDE proxy settings), then reads environment variables like HTTPS_PROXY when DSH starts, and finally scans common ports 7890, 7897, 6152, 1087, 10809, etc. Each candidate address undergoes an actual handshake verification to ensure it is truly an HTTP proxy.

  2. Three lines: auto (follows detection results), forward (fixed through proxy), direct (fixed direct connection). Default auto. Before each web_fetch, the plugin probes the proxy port locally, about 1 millisecond, so it won’t take the wrong line if the proxy was just turned off; if the proxy is not found, it connects directly, and the direct connection security check proceeds as normal.

  3. Switchable scope. Default web_fetch_only, other modules only follow this line when explicitly choosing global.

  4. Manual entry for proxy requiring username/password. Use http://user:pass@address:port. Passwords are only stored locally with permission 600, and are displayed as *** in the interface, logs, and prompts.

  5. Current status attached to web_fetch results. The model can see this and tell you.

Installation and Enablement

In DeepSeek Harness, say the following to the model, then completely exit and reopen DSH:

用 plugin_manager 安装插件 @lightrivers/dsh-proxy-switch

After restarting, a small button will appear at the bottom right of the sidebar, showing the current line and status dot (e.g., “Through Proxy ●”).

If you previously wrote HTTP_PROXY / HTTPS_PROXY in ~/.dsh/.env, delete them before restarting. Otherwise, after the plugin is disabled, DSH will revert to the hardcoded proxy.

README also provides installation steps from source: download source code to ~/dsh-proxy-switch, then say to the model “Use plugin_manager to install plugin ~/dsh-proxy-switch” (it will execute plugin_manager action=install_bundle target=<absolute_path>), then completely exit and reopen DSH. When upgrading, git pull in the source code directory, then execute the installation steps again. This article only summarizes the README original text; for actual installation, please use the official installation method above.

When upgrading from version 0.4.1 and earlier (package name changed to @lightrivers/dsh-proxy-switch starting from 0.4.2), first let the model use plugin_manager to uninstall the old dsh-proxy-switch, then install the new version as above; settings and status will be retained.

Typical usage

Most people don’t need to do anything after installing. The default is “Auto”: the plugin reads system proxy settings, finds the proxy port, web_fetch goes through the proxy while the proxy is running, and automatically switches to direct connection after the proxy is turned off.

Click the button at the bottom of the sidebar to open the panel. Main area:

  • Top large block: Which line is currently being used. Animated lines indicate smooth flow, symbols mark issues (✕ indicates a break there, 🔒 indicates proxy needs login, ❗ indicates instability). Small tag in top right corner is scope: “web_fetch only” or “All Tools”.
  • Auto / Through Proxy / Direct: Select line.
  • Proxy row: Found proxy address, how it was found (System Proxy, Env Var, or Port Scan), and latency; right button can re-detect.
  • More settings: Manually enter proxy address, scope, where to put the button.

Button dots: 🟢 Normal, 🟠 Needs attention, 🔴 Problem, ⚪ Detecting.

The button position at the bottom left of the sidebar can be changed to the top of the conversation bar (suitable for people who often collapse the sidebar, on Windows the default row is hidden when the sidebar is collapsed) or “Do not display”. After selecting “Do not display”, settings remain in the “Plugins -> Proxy Switch” page.

When line and proxy status don’t match, the panel provides a sentence explaining it and a fix button. Follow the instructions on the button: click “Change to Auto” when proxy is on but fixed to direct; click “Manually enter address” when proxy is running but port not found, just fill in the port number (e.g., 7890).

Configuration and Status

Settings that can be changed in the panel are saved in ~/.dsh/storages/dsh-proxy-switch/state.json (directory permission 0700, file permission 0600), generally no need to edit manually.

Field Default Description
mode auto auto / forward (fixed proxy) / direct (fixed direct)
upstreamSource auto When auto, proxy address is updated by detection results; when manual, only manually entered addresses are used
upstream http://127.0.0.1:1082 Proxy address, only accepts http://host:port, can include user:pass@
scope web_fetch_only web_fetch_only (web_fetch only) / global (all tools)
listenPort 7899 Local port used only in “All Tools” mode
probeIntervalMs 15000 Interval for background proxy detection (3000–600000 ms), not provided for modification in the interface

Button placement is a browser-side preference, saved in localStorage as dsh-proxy-switch.placement.

The plugin also provides a local status interface:

GET  /dsh-proxy-switch/state
POST /dsh-proxy-switch/mode      { "mode": "auto" | "forward" | "direct" }
POST /dsh-proxy-switch/settings  { "scope"?, "upstream"?, "upstreamSource"?, "listenPort"?, "probeIntervalMs"? }
POST /dsh-proxy-switch/probe     Immediately probe current proxy once
POST /dsh-proxy-switch/detect    Immediately re-find proxy

The interface only accepts local requests, Host must be DSH’s own address, and validates Origin, Sec-Fetch-Site; POST also requires Content-Type: application/json and request header x-dsh-proxy-switch-request: 1.

How it works

The plugin only replaces the “send request” step of web_fetch: requests first enter the plugin’s own web_fetch provider, then pass through a local private channel (random port, listening only on 127.0.0.1), and are then routed to the HTTP proxy or the target website directly. Redirects, timeouts, size limits, and encoding handling still use DSH’s original implementation.

  • When connecting directly, all DNS results must be public network addresses; fake-IP, internal network, loopback, NAT64 embedded private addresses, etc., are all rejected.
  • When going through a proxy, local names like localhost, .local, .lan and targets resolved to internal addresses on the local machine are rejected, but ultimately resolved by the proxy, so it is only mitigation.
  • The private channel generates a random token on each start; other programs on the local machine cannot borrow it (nor the saved proxy username/password); each request uses a new connection, so after switching lines, the old proxy tunnel is not reused.

Use cases and notes

Suitable:

  • DSH web_fetch fails in TUN / Fake-IP environments
  • Only System Proxy enabled without TUN
  • Want automatic switching when proxy is toggled
  • Want web_fetch results to include status prompts

Need to note:

  • Only supports HTTP proxy (or Mixed Port), SOCKS, PAC not supported. Use http://user:pass@host:port form manually if account/password is needed.
  • Currently fully verified only on macOS, Windows, Linux code is supported but not yet verified on real machines.
  • The plugin runs with the permissions of the current DSH process. It is recommended to read the source code and LICENSE (MIT) before installing to confirm the source is trustworthy.
  • Internal network access blocking when going through proxy is only mitigation, cannot guarantee 100%. When TUN is on, the local machine can only resolve to fake addresses, and the plugin cannot judge the real target; if DNS pollution resolves a normal website to an internal address, that website will be mistakenly rejected when going through the proxy, prompting “Forward mode rejected request”. Opening TUN or switching to a trusted DNS can restore it.
  • README reminder: Plugin dependencies must be written in peerDependencies, not in dependencies, otherwise a second copy of @deepseek-ai/dsh-http-proxy will be installed, and “All Tools” mode will silently fail.
  • README also provides test commands: npm test (unit tests), DSH_RUNTIME_MODULES=/path/to/dsh/node_modules node scripts/e2e-host.mjs (real Cordis/WebRuntime integration tests), node scripts/e2e-real.mjs (optional, tested with real local HTTP proxy), node scripts/e2e-web-fetch-warning.mjs (warning text attached to web_fetch results).

Conclusion

The value of dsh-proxy-switch lies not in new capabilities, but in changing the line selection for web_fetch in proxy environments from “relying on hardcoding HTTP_PROXY and gambling” to “automatic detection, one-click switching, and defaulting not to affect other tools”. Whether to install depends on whether you usually have TUN on or only System Proxy on. Plugin directory page: https://www.skillhub.cn/plugins/lightrivers/dsh-proxy-switch , source code: https://github.com/lightrivers/dsh-proxy-switch .

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye