feat(mdns): añadir resolver genérico + helpers de shell
- bin/resolve: hostname -> IP con orden mDNS (LAN) -> Tailscale -> caché. Reutilizable en cualquier comando (ping, curl, kubectl, nc). - bin/ssh-mdns-proxy: arreglar shebang (#\! -> #!) que hacía fallar declare -A al caer en sh; y reemplazar getent (inexistente en Termux) por python socket.gethostbyname, con detección para portabilidad. - config/bashrc.snippet: añadir aliases r/pingr/sshr/curlr. sshr usa HostKeyAlias para que SSH-por-IP no falle verificación de known_hosts. - docs/03-ssh-mdns-tailscale.md: sección nueva sobre resolve + gotchas (getent ausente, shebang bash-only, mDNS no cruza redes). - install.sh: incluir resolve en la lista de scripts a instalar. - README.md: nueva fila en la tabla de componentes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f7ad71bd3c
commit
5c4e41f6b0
|
|
@ -43,6 +43,7 @@ bash install.sh --dry-run
|
|||
| `mdns-publish.py` | `~/.local/bin/` | Publish this device as `movil.local` (needs `zeroconf`) |
|
||||
| `ssh-mdns-proxy` | `~/.local/bin/` | SSH ProxyCommand: mDNS → Tailscale |
|
||||
| `ssh-fallback` | `~/.local/bin/` | SSH ProxyCommand: Tailscale → LAN fallback |
|
||||
| `resolve` | `~/.local/bin/` | Generic host resolver: mDNS → Tailscale → cache (for any command) |
|
||||
| `settings.json` | `~/.claude/` | Disables auto-updater |
|
||||
|
||||
## Usage
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
#!/data/data/com.termux/files/usr/bin/bash
|
||||
# resolve: hostname -> IP con fallback mDNS (LAN) -> Tailscale DNS -> cache
|
||||
# Uso: resolve <hostname>[.local|.tailnet]
|
||||
# Ej: resolve lenovo # -> 100.69.236.16
|
||||
# ping $(resolve hp62a)
|
||||
# curl "http://$(resolve dell):8080"
|
||||
set -e
|
||||
HOST="${1:-}"
|
||||
[[ -z "$HOST" ]] && { echo "Uso: resolve <hostname>" >&2; exit 1; }
|
||||
|
||||
CACHE="$HOME/.ssh/resolve-cache"
|
||||
TAILSCALE_DOMAIN="${TAILSCALE_DOMAIN:-tailb0bb74.ts.net}"
|
||||
MDNS_TIMEOUT="${MDNS_TIMEOUT:-1}"
|
||||
|
||||
QUERY="${HOST%.local}"
|
||||
QUERY="${QUERY%.${TAILSCALE_DOMAIN}}"
|
||||
|
||||
declare -A ALIASES=(
|
||||
[dell]="dell-latitude3400"
|
||||
[lenovo]="lenovo-ideapad"
|
||||
)
|
||||
[[ -n "${ALIASES[$QUERY]:-}" ]] && QUERY="${ALIASES[$QUERY]}"
|
||||
|
||||
# 1. mDNS multicast (LAN)
|
||||
IP=$("$HOME/.local/bin/mdns-resolve" "${QUERY}.local" "$MDNS_TIMEOUT" 2>/dev/null || true)
|
||||
|
||||
# 2. Tailscale MagicDNS (remoto)
|
||||
if [[ -z "$IP" ]]; then
|
||||
IP=$(python -c "import socket; print(socket.gethostbyname('${QUERY}.${TAILSCALE_DOMAIN}'))" 2>/dev/null || true)
|
||||
fi
|
||||
|
||||
# 3. Cache
|
||||
if [[ -z "$IP" && -f "$CACHE" ]]; then
|
||||
IP=$(grep "^${QUERY} " "$CACHE" 2>/dev/null | awk '{print $2}')
|
||||
fi
|
||||
|
||||
if [[ -z "$IP" ]]; then
|
||||
echo "Error: no se resuelve '${HOST}'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "$CACHE")"
|
||||
grep -v "^${QUERY} " "$CACHE" > "${CACHE}.tmp" 2>/dev/null || true
|
||||
echo "${QUERY} ${IP}" >> "${CACHE}.tmp"
|
||||
mv "${CACHE}.tmp" "$CACHE"
|
||||
|
||||
echo "$IP"
|
||||
|
|
@ -24,9 +24,13 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|||
# 1. mDNS resolution
|
||||
IP=$("$SCRIPT_DIR/mdns-resolve" "${QUERY}.local" 2 2>/dev/null)
|
||||
|
||||
# 2. Fallback: Tailscale DNS
|
||||
# 2. Fallback: Tailscale DNS (Termux carece de getent, usar python si esta disponible)
|
||||
if [[ -z "$IP" ]]; then
|
||||
IP=$(getent hosts "${QUERY}.${TAILSCALE_DOMAIN}" 2>/dev/null | awk '{print $1}')
|
||||
if command -v getent >/dev/null 2>&1; then
|
||||
IP=$(getent hosts "${QUERY}.${TAILSCALE_DOMAIN}" 2>/dev/null | awk '{print $1}')
|
||||
else
|
||||
IP=$(python -c "import socket; print(socket.gethostbyname('${QUERY}.${TAILSCALE_DOMAIN}'))" 2>/dev/null)
|
||||
fi
|
||||
fi
|
||||
|
||||
# 3. Fallback: cached IP
|
||||
|
|
|
|||
|
|
@ -27,6 +27,21 @@ alias mdns-status='pgrep -af mdns-publish || echo "mDNS publisher is not running
|
|||
alias mdns-restart='pkill -f mdns-publish; sleep 1; nohup python ~/.local/bin/mdns-publish.py >>~/.cache/mdns.log 2>&1 & disown && echo "mDNS restarted"'
|
||||
alias mdns-stop='pkill -f mdns-publish && echo "mDNS stopped"'
|
||||
|
||||
# === Generic host resolver (resolve: mDNS -> Tailscale -> cache) ===
|
||||
# Works in any command: ping $(resolve lenovo) / curl "http://$(resolve hp62a)"
|
||||
alias r='resolve'
|
||||
pingr() { ping -c 3 "$(resolve "$1")"; }
|
||||
curlr() { local h="$1"; shift; curl "$@" "http://$(resolve "$h")"; }
|
||||
# HostKeyAlias reuses the known_hosts entry for the Tailscale FQDN
|
||||
# so SSH-by-IP does not fail host-key verification.
|
||||
sshr() {
|
||||
local h="$1"; shift
|
||||
local canonical="$h"
|
||||
case "$h" in dell) canonical="dell-latitude3400";; lenovo) canonical="lenovo-ideapad";; esac
|
||||
ssh -o "HostKeyAlias=${canonical}.${TAILSCALE_DOMAIN:-tailb0bb74.ts.net}" \
|
||||
"YOUR_USER@$(resolve "$h")" "$@"
|
||||
}
|
||||
|
||||
# === Optional: auto-start samba + mDNS on shell login ===
|
||||
# Uncomment the block below if you want services up automatically.
|
||||
# Failures are logged (NOT silenced) — silent failures after a tar restore are the worst class of bug.
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ Termux's Bionic libc does **not** resolve `.local` names. This repo ships small
|
|||
| `mdns-publish.py` | Publish this device on the LAN as `movil.local` (or whatever you choose) using `zeroconf`. |
|
||||
| `ssh-mdns-proxy` | SSH `ProxyCommand` that tries mDNS first, then Tailscale DNS. Used from `~/.ssh/config`. |
|
||||
| `ssh-fallback` | Lower-level fallback: tries Tailscale, then LAN. Useful when Tailscale is flaky. |
|
||||
| `resolve` | Generic resolver for **any** command (ping, curl, kubectl…). Same order: mDNS → Tailscale → cache. |
|
||||
|
||||
## SSH config
|
||||
|
||||
|
|
@ -58,3 +59,41 @@ When you list hosts in `~/.ssh/config`, prefer:
|
|||
2. `<host>.YOUR-TAILNET.ts.net` for off-LAN
|
||||
|
||||
Never hardcode IPs — they rotate.
|
||||
|
||||
## Generic resolver (`resolve`) for any command
|
||||
|
||||
`ssh-mdns-proxy` only helps SSH. For everything else — `ping`, `curl`, `kubectl`, `nc` — use `resolve`. It applies the same lookup order and updates the cache:
|
||||
|
||||
```bash
|
||||
resolve lenovo # -> 100.69.236.16
|
||||
ping $(resolve hp62a)
|
||||
curl "http://$(resolve dell):8080"
|
||||
```
|
||||
|
||||
Environment knobs:
|
||||
|
||||
- `TAILSCALE_DOMAIN` — defaults to `tailb0bb74.ts.net`. Set to your own tailnet.
|
||||
- `MDNS_TIMEOUT` — seconds for multicast (`1` by default, low so remote calls stay snappy).
|
||||
|
||||
Short aliases and helper functions to drop into `~/.bashrc` (see `config/bashrc.snippet`):
|
||||
|
||||
```bash
|
||||
alias r='resolve'
|
||||
pingr() { ping -c 3 "$(resolve "$1")"; }
|
||||
sshr() {
|
||||
local h="$1"; shift
|
||||
local canonical="$h"
|
||||
case "$h" in dell) canonical="dell-latitude3400";; lenovo) canonical="lenovo-ideapad";; esac
|
||||
ssh -o "HostKeyAlias=${canonical}.${TAILSCALE_DOMAIN:-tailb0bb74.ts.net}" \
|
||||
"YOUR_USER@$(resolve "$h")" "$@"
|
||||
}
|
||||
curlr() { local h="$1"; shift; curl "$@" "http://$(resolve "$h")"; }
|
||||
```
|
||||
|
||||
`HostKeyAlias` in `sshr` is important: since we connect by IP, SSH would fail host-key verification otherwise. Aliasing back to the canonical Tailscale FQDN reuses the `known_hosts` entry you already trust.
|
||||
|
||||
## Gotchas found the hard way
|
||||
|
||||
- **`getent` doesn't exist on Termux.** Any script that shells out to it for DNS will silently fail. `resolve` and `ssh-mdns-proxy` fall back to `python -c "import socket; socket.gethostbyname(...)"` — that's the portable way on Bionic.
|
||||
- **Shebang matters.** `#!/data/data/com.termux/files/usr/bin/bash` is required for `declare -A` (associative arrays). A stray backslash (`#\!`) makes the kernel fall through to `sh`, which silently rejects bash-only syntax with `Syntax error: "(" unexpected`.
|
||||
- **mDNS off-LAN is a no-op.** Multicast (224.0.0.251) does not cross networks. Over mobile data the Tailscale fallback is the only path that works.
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ fi
|
|||
# 4. Install scripts
|
||||
step 4 "Installing scripts to $BIN_DIR..."
|
||||
run mkdir -p "$BIN_DIR"
|
||||
for script in clauded claude-check-env claude-update mdns-resolve mdns-publish.py ssh-mdns-proxy ssh-fallback; do
|
||||
for script in clauded claude-check-env claude-update mdns-resolve mdns-publish.py ssh-mdns-proxy ssh-fallback resolve; do
|
||||
run cp "$SCRIPT_DIR/bin/$script" "$BIN_DIR/$script"
|
||||
run chmod +x "$BIN_DIR/$script"
|
||||
done
|
||||
|
|
|
|||
Loading…
Reference in New Issue