red en metal: de udhcpc/ifconfig/route a dhcpcd/ip — y el adduser que NO se migra
Los dos guiones de WiFi que corren DENTRO de la imagen (metal-iso.sh y cosmic/metal-desktop-image.sh) usaban cuatro applets que salen del defconfig: udhcpc, ifconfig, route y el guión de hooks que udhcpc necesita. Los usos eran básicos —subir la interfaz, pedir IP, poner ruta y resolv.conf— así que van a las herramientas ya declaradas en `base`: `ip` de iproute2 y `dhcpcd`. Y el cambio arregla algo de paso, no sólo sustituye: dhcpcd queda de daemon RENOVANDO el lease. Una de las dos causas medidas el 2026-08-06 de que el enlace se cayera solo a mitad de una depuración remota era precisamente que `udhcpc -q` pedía la dirección una vez y nadie la renovaba. El bloque wifi-keep que lo mitigaba sigue (la otra causa, el AP que olvida clientes ociosos, no se toca). `adduser` de alta-usuario.sh NO se migra, y esa es la decisión, no una omisión: `useradd` es de shadow y su modelo nativo es escribir /etc/shadow — el fichero cuya creación dejó a la caja sin aceptar ni la clave de root, con los ocho dominios caídos ~20 min (SDD 28 §6.51). El script tiene un guardián explícito para cazar justo eso. Cambiar el applet por la herramienta «buena» reintroduce el fallo que el guardián existe para atrapar ⇒ `adduser` queda indultado en el defconfig junto a setuidgid, switch_root, halt, poweroff y reboot. El día que la caja adopte shadow de verdad se revisa entero. ⚠ Sin probar en metal: no tengo la laptop acá. El cambio es de una línea por guión y las dos herramientas están en los 7 perfiles, pero quien lo arranque en hardware que mire `ip -4 addr show` antes de dar la red por buena. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Semantic delta
No definition changed: this change is text, documentation or data.
3 files · +27 −22
diff --git a/scripts/cosmic/metal-desktop-image.sh b/scripts/cosmic/metal-desktop-image.sh
index 9b698162..acb65bc6 100755
--- a/scripts/cosmic/metal-desktop-image.sh
+++ b/scripts/cosmic/metal-desktop-image.sh
@@ -270,23 +270,12 @@ while [ $i -lt 40 ]; do
i=$((i + 1)); sleep 1
done
[ "$ST" = COMPLETED ] || echo " ⚠ no asoció (wpa_state=${ST:-?}). 4WAY_HANDSHAKE=clave; SCANNING=no ve la red"
-cat > /tmp/udhcpc.script <<'US'
-#!/bin/sh
-case "$1" in
- bound|renew)
- ifconfig "$interface" "$ip" netmask "${subnet:-255.255.255.0}"
- [ -n "$router" ] && route add default gw "${router%% *}" dev "$interface" 2>/dev/null
- [ -n "$dns" ] && { : > /etc/resolv.conf; for d in $dns; do echo "nameserver $d" >> /etc/resolv.conf; done; }
- ;;
-esac
-exit 0
-US
-chmod +x /tmp/udhcpc.script
-# Tres intentos: el AP a veces no contesta el primer DISCOVER justo tras asociar.
-for t in 1 2 3; do
- udhcpc -i "$IF" -n -q -s /tmp/udhcpc.script && break
- echo " DHCP intento $t sin respuesta, reintento…"; sleep 3
-done
+# DHCP con `dhcpcd` (2026-09-22). Antes era `udhcpc` de busybox + un guión de hooks propio que
+# llamaba a `ifconfig` y `route` — tres applets que salen del defconfig. `dhcpcd` hace las tres
+# cosas (dirección, ruta por defecto, /etc/resolv.conf) sin hooks, reintenta solo cuando el AP no
+# contesta el primer DISCOVER, y **se queda renovando el lease**: eso elimina una de las dos causas
+# del bloque de abajo, donde `udhcpc -q` pedía la dirección una vez y nadie la renovaba.
+dhcpcd "$IF" || echo " DHCP sin respuesta tras los reintentos de dhcpcd"
ip -4 addr show "$IF" | grep -w inet \
|| echo "sin IPv4. Mirá 'wpa_cli -i $IF status': si wpa_state=COMPLETED el problema es DHCP, no la clave"
echo "== desde el laptop: ssh -i ~/.ssh/hammer-metal root@<la IP de arriba> =="
@@ -296,7 +285,8 @@ chmod 0755 "$MERGED/usr/bin/wifi-up"
# ── el enlace WiFi se caía solo y cortaba la depuración a mitad ─────────────────────────────────
# Medido el 2026-08-06 depurando la OptiPlex por SSH sobre un hotspot: la máquina desaparecía de la
# red cada pocos minutos. Dos causas que se suman, y ninguna es «la WiFi anda mal»:
-# - `udhcpc -q` (el que usa wifi-up) pide la dirección UNA vez y termina: nadie renueva el lease.
+# - `udhcpc -q` (el que usaba wifi-up) pedía la dirección UNA vez y terminaba: nadie renovaba el
+# lease. ✅ RESUELTO el 2026-09-22 al migrar a `dhcpcd`, que se queda de daemon renovando.
# - el AP olvida a los clientes ociosos y deja de contestar ARP ⇒ «No route to host» desde fuera,
# mientras la máquina se cree perfectamente conectada. El síntoma engaña: no hay nada en dmesg.
# El ping periódico resuelve las dos a la vez — detecta la caída Y mantiene viva la entrada en el AP.
diff --git a/scripts/metal-iso.sh b/scripts/metal-iso.sh
index 68d637b7..b7e4fb12 100755
--- a/scripts/metal-iso.sh
+++ b/scripts/metal-iso.sh
@@ -62,7 +62,7 @@ scripts/metal-firmware.sh "$AUG"
mkdir -p "$AUG/usr/sbin"
cp "$WPADIR"/wpa_supplicant "$WPADIR"/wpa_cli "$WPADIR"/wpa_passphrase "$AUG/usr/sbin/"
-# 4) helper de conexión WiFi (busybox ip/udhcpc + wpa_supplicant)
+# 4) helper de conexión WiFi (iproute2 + dhcpcd + wpa_supplicant)
cat > "$AUG/usr/bin/wifi-connect" <<'WC'
#!/bin/sh
# wifi-connect SSID [PASSPHRASE] — asocia el WiFi y pide IP por DHCP.
@@ -75,7 +75,7 @@ for d in /sys/class/net/*; do
done
[ -n "$IF" ] || { echo "no hay interfaz wireless (¿cargó iwlwifi? revisá 'dmesg | grep iwlwifi')"; exit 1; }
echo "==> interfaz: $IF"
-ip link set "$IF" up 2>/dev/null || ifconfig "$IF" up
+ip link set "$IF" up
if [ -n "$PSK" ]; then
wpa_passphrase "$SSID" "$PSK" > /tmp/wpa.conf
else
@@ -85,8 +85,14 @@ pkill wpa_supplicant 2>/dev/null || true
wpa_supplicant -B -i "$IF" -c /tmp/wpa.conf -D nl80211
echo "==> asociando… (espera unos segundos; 'wpa_cli status' para ver el estado)"
sleep 4
-udhcpc -i "$IF" -q -n || udhcpc -i "$IF"
-echo "==> listo. IP:"; ip addr show "$IF" 2>/dev/null | grep -w inet || ifconfig "$IF"
+# `dhcpcd` configura IP, ruta por defecto y /etc/resolv.conf él solo —no hace falta guión de
+# hooks— y se queda de daemon RENOVANDO el lease. Reemplaza al `udhcpc` de busybox (2026-09-22):
+# `dhcpcd` está declarado en el perfil `base` y `udhcpc` sale del defconfig.
+# ⚠ Sin `-1` a propósito: `udhcpc -q` pedía la dirección UNA vez y nadie renovaba el lease, que es
+# una de las dos causas medidas de que el enlace se cayera solo a mitad de una depuración remota
+# (ver el bloque `wifi-keep` de scripts/cosmic/metal-desktop-image.sh, 2026-08-06).
+dhcpcd "$IF"
+echo "==> listo. IP:"; ip addr show "$IF" | grep -w inet
WC
chmod +x "$AUG/usr/bin/wifi-connect"
diff --git a/scripts/servidor/alta-usuario.sh b/scripts/servidor/alta-usuario.sh
index ca7d21ae..820fc48e 100755
--- a/scripts/servidor/alta-usuario.sh
+++ b/scripts/servidor/alta-usuario.sh
@@ -12,6 +12,15 @@
# Entonces el alta correcta acá es: crear la cuenta, dejar el hash donde el login lo lee, y
# **comprobar que quien podía entrar sigue pudiendo** antes de darse por satisfecho.
#
+# ⚠ Y por eso este `adduser` NO se migra a `useradd` (2026-09-22). El plan de botar busybox migra
+# los llamadores de applets a las herramientas declaradas —`ip` por `ifconfig`, `dhcpcd` por
+# `udhcpc`— porque esos usos son básicos. Éste no lo es: `useradd` es de `shadow`, y su modelo
+# NATIVO es escribir en `/etc/shadow`, que es justo el fichero que tumbó la caja. Cambiar el applet
+# por la herramienta «buena» reintroduciría el fallo que el guardián de abajo existe para cazar.
+# `adduser` queda INDULTADO en el defconfig de busybox por esta razón, junto a `setuidgid`,
+# `switch_root`, `halt`, `poweroff` y `reboot`. El día que la caja adopte shadow de verdad, esto se
+# revisa entero — no antes, y no de paso.
+#
# Lo demás es lo que hace falta para «tener poder sobre la máquina, a mano y con claude»:
# · `/etc/sudoers.d/<u>` — root a mano (el `sudo` de acá SÍ es setuid; `doas` no funciona)
# · `/etc/sub{u,g}id` — sin rango, un userns anidado no puede mapear uid 0 y `takana build`