Compare commits

...
3 Commits
Author SHA1 Message Date
gandalf 1f51d1818d fix(live-usb): nft rule syntax — udp dport 68 (drop the redundant udp sport)
v2.12.11's rule `udp sport 67 udp dport 68 accept` was invalid nft
syntax — protocol prefix can't be repeated inside a single rule, the
firstboot.sh-generated /etc/nftables.conf failed to load and the
firewall stayed in its previous state (or empty), defeating the
whole point of the DHCP fix.

Just match the destination port: `udp dport 68 accept`. DHCPOFFER /
DHCPACK from any server (sport 67) lands on dport 68 of the client,
so the inbound match is sufficient and unambiguous.

Live-system workaround (no rebuild needed):
  nft add rule inet secubox_filter input udp dport 68 accept
2026-05-26 07:20:33 +02:00
gandalf 8b0ec6884c fix(live-usb): nftables — accept DHCP replies (udp sport 67 dport 68)
Bare-metal box ended up with 192.168.10.250 (assigned by secubox-net-
fallback's ARP-probe loop) instead of the real DHCP lease from the
LAN router. Operator confirmed DHCP server is healthy on the LAN
(dev box on same switch got 192.168.1.13 via DHCP without issue).

Root cause: firstboot.sh writes /etc/nftables.conf with policy=drop
on the input chain and no explicit DHCP allowance. The `ct state
established,related accept` rule does NOT cover DHCP because the
client request leaves from 0.0.0.0:68 and the server reply comes back
broadcast (or unicast direct to the offered IP before it's bound).
Neither matches the original 5-tuple → conntrack treats the reply
as a new packet → policy drop → DHCPOFFER lost → networkd times out.
secubox-net-fallback then picks a random gateway from its probe
list and lands the box on the wrong subnet.

Add `udp sport 67 udp dport 68 accept` to the input chain. This
matches DHCPv4 server-to-client replies specifically (port 67/68
are reserved BOOTP/DHCP). DHCPv6 would need a sibling `udp dport
546 accept` rule but is out of scope here.
2026-05-26 07:16:27 +02:00
gandalf f61932c6c6 revert(live-usb): restore v2.10.3 verbatim GRUB EFI + label-based search
Real UEFI hardware kept landing in grub rescue / grub shell across every
v2.12.x iteration: shim swap, hardened module list, $cmdpath embed,
search --fs-uuid bake-in. None of them shipped a working real-UEFI
boot. v2.10.3 was the last tag the operator confirmed booted his
hardware in both BIOS and UEFI mode.

Drop the experimental UUID capture + the embed-cfg fallback chain.
Restore EXACTLY what v2.10.3 had:

  # embed-cfg
  search --no-floppy --label ESP --set=root
  set prefix=($root)/boot/grub
  configfile $prefix/grub.cfg

  # main grub.cfg LIVE search
  search --no-floppy --label LIVE --set=live

Validated other v2.12.x improvements stay (mass-mask LXC services,
dynamic MOTD, modesetting for VBox, kiosk --no-block) — they don't
touch the boot path.
2026-05-25 17:18:42 +02:00
2 changed files with 20 additions and 39 deletions
+10 -39
View File
@@ -3521,16 +3521,6 @@ else
fi
fi
# Capture UUIDs — labels failed to resolve on at least one real UEFI
# box (v2.12.x grub> shell symptom). Bake UUIDs into the embed-cfg
# and grub.cfg so `search --fs-uuid` is used everywhere instead of
# the fragile `search --label`. blkid is read AFTER mkfs.* so the
# values are guaranteed fresh.
udevadm settle 2>/dev/null || sleep 1
ESP_UUID=$(blkid -s UUID -o value "${LOOP}p2" 2>/dev/null || echo "")
LIVE_UUID=$(blkid -s UUID -o value "${LOOP}p3" 2>/dev/null || echo "")
[[ -z "$ESP_UUID" || -z "$LIVE_UUID" ]] && err "Failed to read ESP/LIVE UUIDs from ${LOOP} after mkfs"
log "ESP UUID=${ESP_UUID} LIVE UUID=${LIVE_UUID}"
# Mount for file copy
MNT="${WORK_DIR}/mnt"
@@ -3582,15 +3572,7 @@ insmod all_video
insmod echo
insmod gfxterm
# Resolve LIVE partition by UUID — `search --label` failed silently on
# real UEFI hardware (v2.12.x grub> shell). UUIDs are baked at build
# time from blkid after mkfs.ext4, so this lookup is deterministic.
search --no-floppy --fs-uuid ${LIVE_UUID} --set=live
# Fallback: keep the label search as a second chance for firmware
# that prefers labels (no-op if already set above).
if [ -z "\$live" ]; then
search --no-floppy --label LIVE --set=live
fi
search --no-floppy --label LIVE --set=live
# CRT-style menu colors (cyan on black, gold highlights)
set menu_color_normal=cyan/black
@@ -3707,28 +3689,17 @@ fi
cp "${MNT}/esp/boot/grub/grub.cfg" "${MNT}/esp/EFI/BOOT/grub.cfg"
# Build GRUB EFI — use $cmdpath, the variable EFI firmware sets to the
# directory it loaded BOOTX64.EFI from. /EFI/BOOT/grub.cfg sits right
# next to BOOTX64.EFI on the ESP (script copies it there above), so
# `configfile $cmdpath/grub.cfg` is a single-step lookup that doesn't
# depend on filesystem labels or partition search — both of which
# have failed on different real-hardware firmware over the v2.12.x
# series. The full grub.cfg itself still does `search --label LIVE
# --set=live` to find the squashfs partition, so that part is
# unchanged.
# Build GRUB EFI — verbatim from v2.10.3 (last known-good real UEFI
# boot). Do NOT optimise this block: every "improvement" attempted in
# the v2.12.x series (Secure Boot shim, $cmdpath, search --fs-uuid,
# extra modules, multi-stage fallbacks) broke at least one piece of
# hardware. Stay simple, stay shipped.
GRUB_MODS="part_gpt part_msdos fat ext2 normal linux boot configfile loopback chain efi_gop efi_uga ls search search_label gfxterm all_video"
cat > "${WORK_DIR}/grub-embed.cfg" <<EMBEDCFG
# Try \$cmdpath first (set by firmware to dir of loaded .EFI). Falls
# back to UUID-based search if \$cmdpath isn't usable.
if [ -n "\$cmdpath" ]; then
configfile \$cmdpath/grub.cfg
fi
search --no-floppy --fs-uuid ${ESP_UUID} --set=root
if [ -n "\$root" ]; then
configfile (\$root)/EFI/BOOT/grub.cfg
fi
echo "GRUB embed-cfg fallback failed: cmdpath=\$cmdpath root=\$root"
cat > "${WORK_DIR}/grub-embed.cfg" <<'EMBEDCFG'
search --no-floppy --label ESP --set=root
set prefix=($root)/boot/grub
configfile $prefix/grub.cfg
EMBEDCFG
grub-mkimage -o "${MNT}/esp/EFI/BOOT/BOOTX64.EFI" \
+10
View File
@@ -443,6 +443,16 @@ table inet secubox_filter {
# HTTP/HTTPS (SecuBox UI)
tcp dport { 80, 443 } accept
# DHCP client — accept DHCPOFFER / DHCPACK on UDP 68. The
# conntrack `established,related` clause above doesn't help
# for DHCP because the request goes out from 0.0.0.0:68 and
# the reply comes back broadcast (or unicast direct to the
# offered IP before it's actually bound), neither of which
# match the original 5-tuple. Without this rule networkd's
# DHCP times out and secubox-net-fallback's ARP-probe takes
# over — operator ends up on a random fallback subnet.
udp dport 68 accept
# WireGuard
udp dport 51820 accept