Configuring a simple router in initrd
Target: Debian Bookworm box with an encrypted root fs
Goal: Enable Remote Unlock but allow the computer to continue to act as a router while it is waiting for someone to unlock the disk
The basic router functions require DHCPd and nftables to be installed and configured in the initramfs prior to a full system boot. It may also require killing the services once the disk has been unlocked so that the primary system services can take over.
Prerequisites
- initramfs-tools
- nftables
- isc-dhcp-server
sudo apt install initramfs-tools isc-dhcp-server nftables
Configure initramfs-tools
Configuring the network interfaces
Configure the internal network interface with a static ip address via kernal command line:
GRUB_CMDLINE_LINUX_DEFAULT="ip=192.168.21.2:::::enp0s25:on panic=30"
This will configure the internal interface with a static ip. For more information on configuring the wifi interface see here. Note that the kernel doesn’t seem to handle multiple ‘ip=’ directives well, at least when one is a wireless device. We will have to add some extras in order to manually bring up the wifi below.
/etc/initramfs-tools/hooks/enable_wireless
# !/bin/sh
set -e
PREREQ=""
prereqs()
{
echo "${PREREQ}"
}
case "${1}" in
prereqs)
prereqs
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
# CHANGE HERE for your correct modules.
manual_add_modules 88XXau cfg80211 usbcore
copy_exec /sbin/wpa_supplicant
copy_exec /sbin/wpa_cli
# Required to manually configure the wifi interface:
copy_exec /usr/sbin/dhclient
copy_exec /sbin/dhclient-script
copy_file config /etc/initramfs-tools/wpa_supplicant.conf /etc/wpa_supplicant.conf
Note: I am copying dhclient and the dhclient-script into my initramfs because the default ipconfig command to retrieve a dhcp lease is not working when I connect to an xfinitywifi hotspot. This is probably due to some anti-spoofing measures on the router. You may be able to omit these lines and use a command such as ‘ipconfig -t 8 -c dhcp -d wlan0’ instead.
/etc/initramfs-tools/scripts/init-premount/a_enable_wireless
#!/bin/sh
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
. /scripts/functions
AUTH_LIMIT=30
INTERFACE="wlan0"
HOSTNAME="servername"
alias WPACLI="/sbin/wpa_cli -p/tmp/wpa_supplicant -i$INTERFACE "
log_begin_msg "Starting WLAN connection"
/sbin/wpa_supplicant -i$INTERFACE -c/etc/wpa_supplicant.conf -P/run/initram-wpa_supplicant.pid -B -f /tmp/wpa_supplicant.log
# Wait for AUTH_LIMIT seconds, then check the status
limit=${AUTH_LIMIT}
echo -n "Waiting for connection (max ${AUTH_LIMIT} seconds)"
while [ $limit -ge 0 -a `WPACLI status | grep wpa_state` != "wpa_state=COMPLETED" ]
do
sleep 1
echo -n "."
limit=`expr $limit - 1`
done
echo ""
if [ `WPACLI status | grep wpa_state` != "wpa_state=COMPLETED" ]; then
ONLINE=0
log_failure_msg "WLAN offline after timeout"
panic
else
ONLINE=1
log_success_msg "WLAN online"
fi
# configure_networking
# Do this manually instead:
hostname $HOSTNAME
/sbin/dhclient -4 -pf /run/initram-dhclient.pid -lf /tmp/dhclient.leases $INTERFACE
Add nftables and all of the required kernel modules to the initramfs:
/etc/initramfs-tools/hooks/enable-nftables
# !/bin/sh
set -e
PREREQ=""
prereqs()
{
echo "${PREREQ}"
}
case "${1}" in
prereqs)
prereqs
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
manual_add_modules nf_tables libcrc32 nfnetlink nft_chain_nat nft_nat nft_masq nft_conntrack nft_defrag_ipv4 nft_defrag_ipv6
copy_exec /usr/sbin/nft
copy_file config /etc/initramfs-tools/nftables.conf /etc/nftables.conf
/etc/initramfs-tools/nftables.conf
#!/sbin/nft -f
flush ruleset
table ip nat {
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
}
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname "wlan0" masquerade
}
}
/etc/initramft-tools/scripts/local-top/enable-nftables
#!/bin/sh
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
. /scripts/functions
# Required or the kernel will refuse to forward packets:
log_begin_msg "Enabling IPv4 forwarding"
sysctl net.ipv4.ip_forward=1
log_begin_msg "Applying NAT rules"
/sbin/nft -f /etc/nftables.conf
EXITCODE=$?
if [ $EXITCODE -ne 0 ]; then
log_failure_message "nft failed with exit status of $EXITCODE"
else
log_success_message "NAT rules applied"
fi
log_end_msg
Configure the dhcpd server:
/etc/initramfs-tools/hooks/enable-dhcpd
# !/bin/sh
set -e
PREREQ=""
prereqs()
{
echo "${PREREQ}"
}
case "${1}" in
prereqs)
prereqs
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
copy_exec /usr/sbin/dhcpd
copy_file config /etc/initramfs-tools/dhcpd.conf /etc/dhcpd.conf
/etc/initramfs-tools/scripts/local-top/enable-dhcpd
#!/bin/sh
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
. /scripts/functions
log_begin_msg "Starting DHCP Server"
touch /tmp/initram-dhcpd.leases
sleep 5 # A workaround because the dhcp server was not starting properly
/sbin/dhcpd -4 -q -cf /etc/dhcpd.conf -lf /tmp/initram-dhcpd.leases -pf /run/initram-dhcpd.pid
EXITCODE=$?
if [ $EXITCODE -ne 0 ]; then
log_failure_message "DHCP Server failed with exit status of $EXITCODE"
else
log_success_message "DHCP Server started"
fi
log_end_msg
/etc/initramfs-tools/scripts/local-bottom/kill-dhcpd
#!/bin/sh
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
echo "Killing initrd DHCP server"
kill `cat /run/initram-dhcpd.pid`
/etc/initramfs-tools/dhcpd.conf
option domain-name "shrikeaero.com";
option domain-name-servers 94.140.14.14, 94.140.15.15;
default-lease-time 600;
max-lease-time 1800; # Use a relatively short lease time
authoritative;
log-facility local7;
subnet 192.168.21.0 netmask 255.255.255.0 {
range 192.168.21.200 192.168.21.254; # Use a different range than the primary service
# to prevent race condition IP address collisions
option routers 192.168.21.1;
}