DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

bemarkt /

bemarkt/dsh-fakeip-compat

Verified

FakeIP compatibility provider for DeepSeek Harness web_fetch — accepts FakeIP-range DNS answers, optional DoH verification, settings row included.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@884adbf4

dsh-fakeip-compat

中文 | English

Version 1.0.0 · verified against DeepSeek Harness 0.2.1-rc.5 on both Desktop and CLI profiles.

A FakeIP-compatibility layer for web_fetch in DeepSeek Harness, with a General-settings row for its own configuration.

When a local DNS answers with placeholder addresses from a FakeIP range, the harness refuses the fetch before a single byte is sent:

Error: URL hostname "raw.githubusercontent.com" resolves to a non-public IP address

This plugin re-registers the http fetch provider with one extra rule ahead of that judgement, and can optionally re-check the real destination through DNS-over-HTTPS. Connection pinning, same-origin redirects, byte and character caps, and charset decoding stay exactly as the harness already does them.

The compat suffix is the point: nothing else changes. The provider id, the row id and the composition are the ones DeepSeek Harness already ships, so this drops into a profile that selects fetchProvider: http without touching anything else.


Table of contents

  • The problem
  • How it works
  • Real-address verification
  • Requirements
  • Install
  • Configure
  • Verify
  • Notes on DeepSeek Harness Desktop
  • Troubleshooting
  • Project layout
  • License

The problem

@deepseek-ai/dsh-web-fetch-http resolves a hostname once and requires every answer to be a globally reachable unicast address (internally ipaddr.js's range() === 'unicast'). A FakeIP resolver answers with addresses from reserved or unique-local blocks, so every request is refused:

Answer ipaddr.js range Outcome
198.18.0.0/15 reserved treated as non-public, rejected
fc00::/18 uniqueLocal treated as non-public, rejected

Any hostname resolving into such a range cannot be fetched by the agent at all.

How it works

One rule is inserted ahead of the stock judgement:

destination inside fakeipRanges  -> allow
allowNonPublic === true          -> allow (the check is skipped entirely)
anything else                    -> the unchanged public-unicast check

Private networks, loopback and the 169.254.169.254 metadata address stay blocked by default.

Design choices worth knowing about:

  • Zero dependencies. IPv4/IPv6 parsing, CIDR matching and the non-public block table live in lib/ip.js. A profile-installed bundle can only resolve its own node_modules, so the plugin must not need one.
  • The stock transport is reused when reachable. The resolver is passed as the second constructor argument of the harness's own HttpFetchProvider, so pinning, redirects, caps and decoding are the shipped implementation rather than a copy.
  • A Node-native fallback exists. If the shipped module cannot be resolved, an equivalent node:http/node:https transport takes over: pinning and caps still apply, the harness proxy router does not. runtime.implementation reports which one is live.
  • The shipped row is disabled, not replaced. The bundle patch turns off web-fetch-http only because two providers cannot share the id http.

Real-address verification

A FakeIP answer says nothing about the real destination: the resolver hands out a placeholder and the proxy resolves the name afterwards. A hostname pointed at a private network therefore arrives looking exactly like any other placeholder.

Turning on verification asks an independent JSON DoH endpoint for the real answer before the connection is made:

verifyRealAddress Behaviour
off (default) no query at all, zero added latency
warn query, log a non-public real answer, then allow the fetch
enforce query, refuse the fetch when the real answer is non-public

dohFailurePolicy decides what an unverifiable destination means while verification is on: allow (default) or deny. Only queries that produced no usable answer count as unverifiable; a query that answered with public addresses is a pass.

Why it is off by default. Verification is not free, and the honest tradeoffs are worth stating:

  • The two DNS views can disagree. A split-horizon or policy-based resolver legitimately returns different answers than a public endpoint. In enforce mode that disagreement becomes a failed fetch, so enforce suits a home network whose only split is the proxy, not a policy-heavy deployment.
  • A failed query is not a verdict. Treating "could not ask" as "not allowed" turns a DNS outage into a broken web_fetch, which is why the failure policy is separate and defaults to allow.
  • It leaks the browsing intent. Every verified hostname is visible to the DoH operator, which a user who set up a local resolver may specifically not want.
  • Literal addresses are never verified. An IP literal is stated by the caller, and the main paths are already covered: literals are classified directly, and DNS rebinding cannot win because the connection is pinned to the address set that was validated.

So verification closes one specific gap — a name whose real answer is a private address — and pays for it in availability, latency and privacy. Off by default; turn it on when that gap is the thing you care about.

Requirements

Item Value
DeepSeek Harness 0.2.1-rc.5 (verified), Desktop and CLI profiles alike
Node.js 20 or newer
Composition must mount web; the settings row additionally needs webServer and configEditor

Without webServer or configEditor (for example a pure TUI profile) the fetch provider still works; the settings row reports that the configuration route is unavailable, and the row config is written by hand.

Install

plugin_manager { action: "install_bundle", target: "<absolute path to this repository>" }

Reinstalling over an existing copy is refused (already-installed); remove first, then install:

plugin_manager { action: "remove_bundle", target: "dsh-fakeip-compat" }
plugin_manager { action: "install_bundle", target: "<absolute path to this repository>" }

The bundle patch does two things:

- id: web-fetch-http      # disabled only to avoid a duplicate "http" provider id
  disabled: true
- insert:
    - id: fakeip-compat
      name: 'dsh-fakeip-compat'
      config:
        fakeipRanges: ['198.18.0.0/15']
        allowNonPublic: false
        verifyRealAddress: 'off'

A tarball install from GitHub works too: package.json records the canonical sources under dsh.install (tarball preferred), so the URL never has to be guessed.

Does it need a restart?

  • Host half (fetch provider and configuration route): live as soon as the install reports application: applied. A saved config reconciles the row through the Loader, so no restart is needed.
  • Client half (the settings row): the browser module graph is composed at startup. A first install, or any edit to client.js, needs a restart before the row appears.

Configure

Settings → General → scroll to the bottom → FakeIP fetch compatibility:

  • FakeIP ranges — a chip list. Type a CIDR block and press Enter to add it; duplicates are ignored, × removes one. An empty list means every non-public destination stays blocked.
  • Allow every non-public destination — the allowNonPublic checkbox.
  • Real-address verification — off / warn / enforce, plus the DoH endpoint and the failure policy.
  • Save — writes the row config into the profile's cordis.patch.yml; the Loader reconciles the row and the provider reloads with the new settings.

Write path:

browser → GET|POST /ext/fakeip-compat/config
        → configEditor.edit(entry, …)
        → ~/.dsh/profiles/<profile>/cordis.patch.yml
        → Loader reconciles the row
        → provider reloads with the new config

Row config

Field Default Meaning
fakeipRanges ['198.18.0.0/15'] CIDR blocks accepted as destinations. Multiple entries, IPv4 and IPv6 mixed.
allowNonPublic false Drop the destination check entirely, private and loopback addresses included.
verifyRealAddress 'off' off / warn / enforce, as described above.
dohEndpoint 'https://dns.google/resolve' JSON DoH endpoint used while verification is on. HTTPS only.
dohTimeoutMs 4000 Per-query deadline for the DoH lookup.
dohFailurePolicy 'allow' What an unverifiable destination means while verification is on.
maxResponseBytes 5000000 Response body byte cap.
maxBodyChars 100000 Decoded character cap.
timeoutMs 30000 Fetch timeout.
maxRedirects 5 Same-origin redirect hop cap.
userAgent deepseek-harness/… Request User-Agent.
- id: fakeip-compat
  name: 'dsh-fakeip-compat'
  config:
    fakeipRanges:
      - '198.18.0.0/15'
      - 'fc00::/18'
    allowNonPublic: false
    verifyRealAddress: 'warn'
    dohEndpoint: 'https://dns.google/resolve'
    dohFailurePolicy: 'allow'

Verify

1. Configuration route. Replace the port with the one the running GUI uses:

Invoke-WebRequest -Uri 'http://127.0.0.1:<PORT>/ext/fakeip-compat/config' -UseBasicParsing | Select-Object -ExpandProperty Content

Expect HTTP 200, rowId: fakeip-compat, the resolved config, and a runtime block:

{
  "rowId": "fakeip-compat",
  "config": { "fakeipRanges": ["198.18.0.0/15"], "allowNonPublic": false, "verifyRealAddress": "off" },
  "runtime": {
    "desktop": true,
    "electron": "44.7.0",
    "node": "24.21.0",
    "dshVersion": "0.2.1-rc.5",
    "implementation": "shipped-http",
    "verifyRealAddress": "off",
    "shippedPath": "…/dsh-web-fetch-http/lib/index.js",
    "resolvedFrom": "…/dsh/package.json"
  }
}

runtime is diagnostic only; it is deliberately not rendered in the settings row.

2. Settings row.

cordis_inspect_query { platform: "client", provider: "Slots", method: "listSubTree", input: { root: "settings.general.item" } }

occupants should contain { "id": "fakeip-compat", "order": 101, "active": true }.

3. Fetch. A URL that used to fail now returns a body:

web_fetch { url: "https://raw.githubusercontent.com/nodejs/node/main/README.md" }

4. Offline self-test. No DNS, no network:

node scripts/selftest.mjs

Covers CIDR boundaries (198.18.0.0 and 198.19.255.254), fc00::/18 inside and outside, ::ffff: mapping, private/loopback/metadata still refused, malformed CIDR rejected, config validation of every verification field, and URL policy.

Notes on DeepSeek Harness Desktop

Desktop is an Electron application, which changes three things for a profile-installed bundle:

Item Value
Harness tree <...>/resources/app/dsh/ (inside app.asar for some distributions)
Profile directory ~/.dsh/profiles/<profile>
Web GUI http://127.0.0.1:<random port> — the port changes on every restart
Client bundle hot reload none; editing client.js needs a restart

The shipped provider is located by probing, in order:

  1. a bare import('@deepseek-ai/dsh-web-fetch-http')
  2. process.resourcesPath/app/dsh/package.json (the Desktop main path)
  3. process.resourcesPath/app/package.json (packaged asar layout)
  4. process.argv[1] (CLI entry)
  5. dirname(process.execPath)/resources/app/dsh/package.json
  6. process.cwd()/package.json
  7. $DSH_PROFILE_DIR/package.json

If none resolves, the Node-native fallback takes over: fetching still works and the caps still apply, but the harness proxy router is bypassed. runtime.implementation tells the two apart.

Troubleshooting

Symptom Cause Fix
WEB_DUPLICATE_PROVIDER the web-fetch-http row was not disabled check - id: web-fetch-http / disabled: true in the patch
still WEB_BLOCKED_URL the range is not in fakeipRanges the error names the address; add that block to the list
WEB_BLOCKED_URL mentioning verifyRealAddress is 'enforce' the real answer is non-public and mode is enforce switch to warn, or drop that host from scope
every fetch fails once verification is on the DoH endpoint is unreachable and dohFailurePolicy is deny fix the endpoint, or set the policy to allow
row says the configuration route is unavailable, (HTTP 404) /ext/fakeip-compat/config was never registered: no webServer, or this row activated before it the plugin waits for webServer via ctx.inject; if it persists, restart DSH
… (HTTP 503) no configEditor in the composition a TUI-only profile has no settings row; write cordis.patch.yml by hand
… row is not present in this profile the row id is not fakeip-compat restore the default id
save reports is overridden by a home patch or command-line overlay a higher-priority patch pins that row's config edit the $DSH_HOME layer or the --patch overlay instead
the row never appears in Settings the client half never entered the module graph confirm every dsh.client.inject package exists in this version, then restart DSH
runtime.implementation is node-native the shipped HttpFetchProvider was not resolved extend the probe list above; fetching works, proxy routing does not

Project layout

dsh-fakeip-compat/
├── .github/workflows/    # CI: syntax check, offline self-test, manifest validation
├── package.json          # name, version, main, exports, dsh.bundle + dsh.client
├── cordis.patch.yml      # bundle patch: disable the shipped row, insert this one
├── client.js             # Client half: window.__ModuleLoader__.load + settings.general.item
├── lib/
│   ├── index.js          # Host half: provider, resolution probing, config route, runtime facts
│   ├── ip.js             # IPv4/IPv6 parsing, CIDR matching, block table, classifier
│   ├── resolver.js       # one resolve, per-answer verdict, optional verification, abort racing
│   ├── doh.js            # optional JSON DoH verification of the real destination
│   ├── provider.js       # node:http/https fallback transport
│   ├── config.js         # DEFAULTS / normalizeConfig / ROW_ID
│   └── config-route.js   # GET/POST /ext/fakeip-compat/config
├── locale/{en,zh}.json   # Plugin Manager title and description
├── icon.svg              # Plugin icon
├── scripts/selftest.mjs  # Offline self-test
├── CHANGELOG.md          # Release history
└── LICENSE

Uninstall

plugin_manager { action: "remove_bundle", target: "dsh-fakeip-compat" }

Removing the bundle drops the web-fetch-http override with it, so the shipped behaviour returns and FakeIP destinations are refused again.

License

MIT

—/ 5

No ratings yet

Verified DSH bundle

Commit 884adbf4323b

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout