You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Redirect bundled Bun's c-ares to a reachable resolv.conf (#26)
Bundled Bun's c-ares resolver (its node:http/axios path: WebFetch's
domain preflight, the claude.ai MCP connector, OTEL export) reads the
absolute /etc/resolv.conf. Android maps /etc -> /system/etc, which has
none, so those lookups hang until timeout while Bun's native fetch
(separate DNS) stays fine. Regressed on Claude releases after 2.1.185.
Ship a second freestanding LD_PRELOAD shim, resolv-redirect.so, that
rewrites opens of /etc/resolv.conf to $PREFIX/etc/resolv.conf. c-ares
reads the file via fopen (opaque FILE*), so the shim reaches the real
function through dlsym(RTLD_NEXT, ...); dlsym is left undefined and
resolved from libc.so.6 with no -ldl, so the object carries no
DT_NEEDED (a libdl.so dep would break the glibc ld.so load). The open
family guards its mode va_arg on O_CREAT/O_TMPFILE, fails closed when a
symbol can't be resolved, and the *64 variants are aliases of their
bases. The launcher preloads uname-spoof.so:resolv-redirect.so.
Validated end-to-end on the affected 2.1.198 via the built .deb:
WebFetch goes from the "unable to verify domain" error to success,
while rg/bfs dispatch and startup stay green.
Closes#25
finds nameservers instead of hanging on a timeout (see `src/resolv-shim.c` and
41
+
issue #25). It also
36
42
**sets `TMPDIR`/`CLAUDE_CODE_TMPDIR`** to the Termux prefix when unset (Termux
37
43
has no writable `/tmp`; see `src/claude-wrapper.c` for the
38
44
env-vs-hardcoded-`/tmp` analysis and the MCP-browser-bridge limitation,
@@ -65,14 +71,15 @@ publish the binary; the `.deb` contains no Anthropic bytes.
65
71
|`package/payload/libexec/link-native.sh`| Idempotent native-path symlink (`~/.local/bin/claude` → launcher) reconcile, shared by `postinst` and the update command. |
66
72
|`package/payload/libexec/patch-execpath.py`| The `CLAUDE_CODE_EXECPATH` patch. |
67
73
|`package/payload/etc/claude-code-termux.conf`|`CLAUDE_CODE_VERSION` pin + `CLAUDE_CODE_CACHE_DIR` (both empty by default). |
68
-
|`src/claude-wrapper.c`| The C launcher (`-DBINARY=`/`-DTMPDIR_PATH=`/`-DUNAME_SHIM=` baked in at compile). `claude_wrapper_run()` takes its exec function as a parameter — a seam the unit tests fake. |
74
+
|`src/claude-wrapper.c`| The C launcher (`-DBINARY=`/`-DTMPDIR_PATH=`/`-DUNAME_SHIM=`/`-DRESOLV_SHIM=` baked in at compile). `claude_wrapper_run()` takes its exec function as a parameter — a seam the unit tests fake. |
69
75
|`src/uname-shim.c`| Freestanding `LD_PRELOAD``uname()` interposer reporting kernel `5.10.0`, so Bun avoids the `epoll_pwait2` startup segfault (bun#32489). Built by `build-wrapper.sh`, shipped to `lib/claude-code-termux/uname-spoof.so`, preloaded by the launcher. |
76
+
|`src/resolv-shim.c`| Freestanding `LD_PRELOAD``fopen`/`open`-family interposer that redirects the absolute `/etc/resolv.conf` (absent on Android) to `$PREFIX/etc/resolv.conf`, so bundled Bun's c-ares resolves DNS on its `node:http` path (WebFetch/claude.ai-MCP/OTEL) instead of hanging (issue #25). References `dlsym` as an undefined symbol resolved from `libc.so.6` — **no `-ldl`**, so zero `DT_NEEDED` (a `libdl.so` dep would break the glibc `ld.so` load). Built by `build-wrapper.sh`, shipped to `lib/claude-code-termux/resolv-redirect.so`, preloaded by the launcher alongside the uname shim. |
70
77
|`test/wrapper_test.c`| Unit tests for the launcher (greatest; recording exec stub). |
71
78
|`test/install_test.sh`| Hermetic unit tests for `install.sh`'s pure helpers (shUnit2; no network/apt). |
72
79
|`test/compat.h`| Test-only `setenv`/`unsetenv` shims for Windows libc; force-included into the test build, never shipped. |
73
80
|`vendor/greatest.h`| Vendored single-header test framework (greatest 1.5.0, ISC; from silentbicycle/greatest). |
74
81
|`vendor/shunit2`| Vendored single-file shell test framework (shUnit2 2.1.9pre, Apache-2.0; pinned to kward/shunit2 master @ `f39734a` — no tagged release since 2.1.8, and master carries the `egrep`→`grep -E` fix we'd otherwise patch). Drives `scripts/e2e.sh` and `test/install_test.sh`. Carries one local patch (grep `PATCHED FOR TERMUX`; re-apply on bump): `#! /bin/sh` stub scripts → resolve `sh` via PATH (submitted upstream as kward/shunit2#189). |
75
-
|`scripts/build-wrapper.sh`| Compile the wrapper + uname shim with Termux's clang. |
82
+
|`scripts/build-wrapper.sh`| Compile the wrapper + uname/resolv shims with Termux's clang. |
0 commit comments