Einen Router bauen
arrow.gif Entwicklungsumgebung
arrow.gif Hardware Plattformen
arrow.gif Slackware Router
arrow.gif Downloads
   
Weiterentwicklung
arrow.gif Tasks pending
arrow.gif Bugs
   
Informationen
arrow.gif Security
arrow.gif FAQ
arrow.gif Links
 
Slackware Linux Router
Prev

19. Ramdisk Router

1.1 Hintergrund

Hardware Plattformen wie Soekris net6501-30 stellen mit 512MB RAM genügend Memory zur Verfügung, um Linuxrouter in einer Ramdisk zu betreiben. Die Vorteile liegen auf der Hand, bei Verdacht auf ein korrumpiertes System genügt ein Reboot um den Router in seinen Ausgangszustand zurückzuführen. ( Um dann die nötigen Schritte einzuleiten, damit ein erfolgreicher Angriff nicht wiederholt werden kann. )

Linuxrouter wird auch in seiner Ramdisk Version als standalone Maschine betrieben, da sonst ein separater Bootserver bereitgestellt werden müsste, der das System zur Verfügung stellt. Mit anderen Worten, es handelt sich nicht um eine «diskless» Maschine.

19.2 Systembau

Der Aufbau des Ramdisk Systems erfordert die folgenden Schritte:

-Linuxrouter wird in die Partition /dev/sda1 eines üblichen Datenträgers installiert.
-Der Router wird gebootet und das System nach /boot/sysimg.tar kopiert.
-Es wird eine initrd angelegt, die /dev/sda1 mountet, eine Ramdisk erzeugt, /boot/sysimg.tar in die Ramdisk entpackt, /dev/sda1 umountet und einen pivot_root durchführt.
-Der Bootmanager erhält einen Eintrag, der den Router via initrd startet.

19.3 Systemträger

Als Systemträger wurde eine 120GB SSD ( Solid State Disk ) mit folgendem Aufbau verwendet.

sda1	750MB	ext2	/	primary		Slackware 11.0 rtr_v0.50 
sda2	75MB	ext2  	/	primary
sda5	1GB	swap		logical
sda6	118GB	ext2	/vol_b	logical 
 

Erklärung:
-Die SSD wurde aufgrund ihrer grösseren Zuverlässigkeit ( gegenüber einem USB Stick) gewählt.
-Da genügend Platz zur Verfügung steht, wird eine Swap Partition eingerichtet.
-/dev/sda2 ist eine Reservepartition. Falls in der logischen Partition je ein weiteres System installiert werden soll, kann /dev/sda2 das /boot Directory aufnehmen − was nötig sein kann, um das Booten zu ermöglichen (BIOS 1024 cylinder limitation ).

19.4 Kernel Konfiguration

Kernel 2.6.39 muss mit initramfs sowie mit initrd Support kompiliert werden.

General Setup -->
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
 
Device Drivers --> 
[*] Block devices -->
  [*] RAM block device support 
  (16)  Default number of RAM disks
  (16384) Default RAM disk size (kbytes)
 

19.5 /etc/fstab anpassen

/etc/fstab muss an die Besonderheiten des Ramdisk Systems angepasst werden.

Dazu werden zwei Versionen des Files angelegt, /etc/fstab.std und /etc/fstab.ramboot:

# /etc/fstab.std
/dev/sda1	/		ext2		defaults	1   1
/dev/sdb1	/media/usb	vfat,ext2,ext3,iso9660  rw,noauto,user,exec  0   0
devpts		/dev/pts	devpts		gid=5,mode=620	0   0
proc		/proc		proc		defaults	0   0
usbfs		/proc/bus/usb	usbfs		defaults	0   0
sysfs		/sys		sysfs		defaults	0   0
tmpfs		/dev/shm	tmpfs		nodev,nosuid,noexec	0   0

# /etc/fstab.ramboot
none             /                 tmpfs        defaults        0   0
/dev/sdb1        /media/usb        vfat,ext2,ext3,iso9660   rw,noauto,user,exec  0   0
devpts           /dev/pts          devpts      gid=5,mode=620   0   0
proc             /proc             proc        defaults         0   0
usbfs            /proc/bus/usb     usbfs       defaults         0   0
sysfs            /sys              sysfs       defaults         0   0
tmpfs            /dev/shm          tmpfs  nodev,nosuid,noexec   0   0
 

Anschliessend wird ein Softlink auf /etc/fstab.std angelegt. ( Beim Kopieren des Systems wird der Link umgeschrieben, so dass das Ramdisk System mit der /etc/fstab.ramboot startet. )

# cd /etc
# ln -s fstab.std fstab
 

19.6 /etc/rc.d/rc.S anpassen

Bei «normalen» Bootups wird das Root Filesystem des Systems mittels e2fschck auf Fehler untersucht.

Wenn in eine Ramdisk gebootet wird, ist diese Überprüfung überflüssige und erzeugt lediglich die Fehlermeldung:

ERROR: Root partition has already been mounted read-write. Cannot check!

Daher muss das Startscript /etc/rc.d/rc.S ebenfalls modifiziert werden − zugegebenermassen ein «ugly hack», Vorschläge, wie dieser vermieden werden kann, sind willkommen.

/etc/rc.d/rc.S wird somit ebenfalls in zwei Versionen geführt, /etc/rc.d/rc.S.std und /etc/rc.d/rc.S.ramboot.

Slackware 11.0 /etc/rc.d/rc.S verzichtet auf eine Überprüfung des Filesystems, wenn dieses vom Typ umsdos ist. Für /etc/rc.d/rc.S.ramboot genügt es somit, an zwei Stellen «umsdos» durch «tmpfs» zu ersetzen. Damit wird auf die Überprüfung der Ramdisk verzichtet.

# /etc/rc.d/rc.S.ramboot
# lines 140ff
...
echo "Testing root filesystem status:  read-write filesystem"
#if cat /etc/fstab | grep ' / ' | grep -wq umsdos ; then
#    ROOTTYPE="umsdos"
#fi
#if [ ! "$ROOTTYPE" = "umsdos" ]; then # no warn for UMSDOS

if cat /etc/fstab | grep ' / ' | grep -wq tmpfs ; then
    ROOTTYPE="tmpfs"
fi
if [ ! "$ROOTTYPE" = "tmpfs" ]; then # no warn for tmpfs 
...
 

Anschliessend wird ein Softlink auf /etc/rc.d/rc.S.std angelegt.

# cd /etc/rc.d
# ln -s rc.S.std rc.S
 

19.7 Bootmanager

Der Bootmanager muss den Router via initrd starten. Linuxrouter v0.50 verwendet lilo, die zugehörige lilo.conf benötigt somit die folgenden Einträge.

# /etc/lilo.conf
# 2016-01-12
#
# Comment the following two entries out after the first install on the development machine.
#disk=/dev/sdd  bios=0x80        # Overrides BIOS' harddisk order, makes BIOS see sdd as sda.
#boot=/dev/sdd                   # Where lilo installs its boot block.

boot=/dev/sda
map=/boot/map
install=text
default=ramboot
lba32
read-only
prompt
timeout=50

# LILO bootable partitions config   
image=/boot/linux
    label=linux
    root=/dev/sda1
    append="console=tty0 console=ttyS0,9600n8r"

image=/boot/linux
    label=ramboot
    root=/dev/sda1
    initrd=/boot/initrd.gz
    append="console=tty0 console=ttyS0,9600n8r"
 

19.8 initrd-tree anpassen

Die Vorlage für das Minimalfilesystem, das von /usr/sbin/mkintrd auf die initrd kopiert wird, befindet sich im Tarfile /usr/share/mkinitrd/initrd-tree.tar.gz.

Unix Systembefehle wie cp, mount, etc., die darin enthalten sind, werden via BusyBox bereitgestellt. Leider ist die BusyBox, die im initrd-tree von Slackware 11.0 zur Anwendung kommt, ohne tar Support kompiliert. Somit kann das System Archiv /boot/sysimg.tar beim Booten nicht in die Ramdisk entpackt werden.

Da die BusyBox statisch gelinkt ist, ist Abhilfe jedoch recht einfach. Wir benützen das Archiv /usr/share/mkinitrd/initrd-tree.tar.gz eines neueren Systems, beispielsweise von Slackware 13.0. Das Vorgehen ist wie folgt:

Den initrd-tree eines Slackware 13.0 Systems auf den Router kopieren und im /tmp Verzeichnis entpacken.

# mkdir /tmp/slack13
# cp initrd-tree_slack13_orig.tar.gz /tmp/slack13
# cd /tmp/slack13
# tar -xzvf initrd-tree_slack13_orig.tar.gz
# rm initrd-tree_slack13_orig.tar.gz
 

Den initrd-tree von Linuxrouter sichern und ebenfalls im /tmp Verzeichnis entpacken.

# mv /usr/share/mkinitrd/initrd-tree.tar.gz /usr/share/mkinitrd/initrd-tree_slack11.tar.gz
# mkdir /tmp/slack11
# cp /usr/share/mkinitrd/initrd-tree_slack11.tar.gz /tmp/slack11
# cd /tmp/slack11
# tar -xzvf initrd-tree_slack11.tar.gz
 

Den initrd-tree von Slackware 13.0 an die Gegebenheiten von Slackware 11.0 anpassen.

# cd /tmp/slack13
# mkdir ramboot
# rm init
# cp ../slack11/linuxrc .
# cp ../slack11/linuxrc linuxrc00
# cd bin
# ln -s busybox chroot
# ln -s busybox insmod
# ln -s busybox pivot_root
 

Die Konfigurationsdatei /tmp/slack11/linuxrc derart anpassen, dass beim Booten des Systems via initrd eine funktionsfähige Ramdisk erstellt wird. Die folgenden Anpassungen sind notwendig.

# linuxrc
...
# Mount root filesystem on rootdev to /mnt
#mount -o ro -t $ROOTFS $ROOTDEV /mnt
mount -o ro -t ext2 /dev/sda1 /mnt

# Create root ramdisk
mount -t tmpfs -o size=256M /dev/ram2 /ramboot

# Copy  your sysimg.tar file over to the ramdisk
cd /ramboot
tar  xf /mnt/boot/sysimg.tar
umount /mnt

## Uncomment for debugging
#echo "list /ramboot content"
#ls /ramboot
#echo "show mounted devices"
#mount
...
# OK, in case there's no initrd directory:
# ( NOTE: The directory for the old root must exist before calling pivot_root. )
if [ ! -d /ramboot/initrd ]; then
  mkdir -p /ramboot/initrd
fi

# bye now
echo "/boot/initrd.gz:  exiting"
pivot_root . initrd
exit 0
 

Damit kann der initrd-tree neu gepackt werden.

# cd /tmp/slack13
# tar czvf /usr/share/mkinitrd/initrd-tree_slack13_custom.tar.gz .
 

Die neu angelegten Verzeichnisse in /tmp werden nicht mehr benötigt.

# cd /tmp
# rm -rf slack11
# rm -rf slack13
 

Das neu erstellte Archiv /usr/share/mkinitrd/initrd-tree_slack13_custom.tar.gz mittels Softlink systemkonform benennen.

# cd /usr/share/mkinitrd/
# ln -s initrd-tree_slack13_custom.tar.gz initrd-tree.tar.gz
 

Als letztes muss das Script /usr/sbin/mkintrd gesichert und wie folgt angepasst werden.

# cd /usr/sbin
# cp mkinitrd mkinitrd00
 
# /usr/sbin/mkintrd
# line 87
...
 # PAD=98
 PAD=1536
...
 

19.9 initrd anlegen

Mit Hilfe des angepassten Archivs initrd-tree.tar.gz kann nun eine initrd für den Ramdisk Router angelegt werden.

Der Aufruf von /usr/sbin/mkintrd mit Parametern bewirkt:

-dass das File /boot/initrd.gz angelegt wird,
-dass das Verzeichnis /boot/initrd-tree/ angelegt wird.

Der Aufruf von /usr/sbin/mkintrd ohne Parametern bewirkt:

-dass ein neues File /boot/initrd.gz angelegt wird, das den Inhalt von /boot/initrd-tree übernimmt.

Mit anderen Worten: Wenn die /boot/initrd.gz erstmalig erzeugt wird, werden die relevanten Parameter angegeben:

# mkinitrd -c  -f ext2 -r /dev/sda1

 -c : Clear the existing initrd tree /boot/initrd-tree
 -f : Specify the filesystem to use for the root partition. Use together with -r
 -r : Specify the device to be used as the root partition
 -k : Use kernel modules from the specified version
 -o : The file to write the initrd to, this is /boot/initrd.gz by default
 

( In der hier diskutierten Konfiguration ist der Aufruf von «-f» und «-r» nicht wirklich nötig, da die entsprechenden Werte bereits in die Konfigurationsdatei /boot/initrd-tree/linuxrc geschrieben wurden. )

Wenn anderseits nachträgliche Anpassungen am File /boot/initrd-tree/linuxrc vorgenommen werden, dann muss die neue /boot/initrd.gz mit dem folgenden Kommando erstellt werden ( ansonsten /boot/initrd-tree/ ebenfalls neu erstellt und damit überschrieben wird ):

# mkinitrd
 

Es ist somit keine schlechte Idee, das File /boot/initrd-tree/linuxrc nach Änderungen zumindest lokal zu sichern!

# cp /boot/initrd-tree/linuxrc /boot/linuxrc_current
 

Hinweis: Immer wenn das /boot/initrd.gz File neu angelegt wird, muss anschliessend lilo aufgerufen werden, damit /boot/initrd.gz beim Booten erkannt wird.

# lilo
 

19.10 System kopieren

Damit ist das System derart vorbereitet, dass es kopiert und ins Archivfile /boot/sysimg.tar geschrieben werden kann, das dann seinerseits beim Booten in die Ramdisk entpackt wird.

Dafür steht das folgende Script /boot/create_rtr05_bootimg.sh zur Verfügung.

Anmerkung: Die Kopieroption -x (--one-file-system) bewirkt, dass der Kopiervorgang nur innerhalb des lokalen Filesystems stattfindet, und dass gemountete Filesysteme nicht kopiert werden. Damit werden die Pseudofilesysteme /proc und /sys nicht kopiert und es wird auch vermieden, dass cp versucht, das kopierte System rekursiv erneut zu kopieren, denn die Kopie wird in eine Ramdisk geschrieben und diese besitzt ein tmpfs. Es ist somit möglich, ein laufendes System korrekt und vollständig zu kopieren (eine nützliche Erkenntnis, denn damit ist es auch möglich ein beliebiges System, beispielsweise einen Server, im laufenden Betrieb zu sichern).

#!/bin/sh
#
# /boot/create_rtr05_bootimg.sh
#
# First completed	2015-12-26
# Last  changed		2016-02-24
#
# rolf.burkart@linuxrouter.ch
#
# Description:
# Script takes an OS snapshot, and writes it to /boot/sysimg.tar
#
# Usage: 
# Run script as root to create a tar archive of your current
# router OS. Run this script again after making changes to 
# the parent OS to update the ramdisk system as well.
#
# ==============================================
# User variables
# ==============================================
#
FSTAB_STD="/etc/fstab.std"
FSTAB_RAMBOOT="/etc/fstab.ramboot"
RC6_STD="/etc/rc.d/rc.S.std"
RC6_RAMBOOT="/etc/rc.d/rc.S.ramboot"

BOOT="/boot"
RAMDISK="/mnt/ramdisk"
RAMDISK_SIZE="256M"
SYSIMG="sysimg.tar"
SHELLSCRIPT_PATH="/boot/create_rtr05_bootimg.sh"
LOG_PATH="/var/log"
#
# ==============================================
# Code section
# ==============================================
#
# Check if fstab files exist.
if [ ! -f ${FSTAB_STD} ]; then
    echo "File ${FSTAB_STD} does not exist. Aborting... "
    exit 1
fi
if [ ! -f ${FSTAB_RAMBOOT} ]; then
    echo "File ${FSTAB_RAMBOOT} does not exist. Aborting... "
    exit 1
fi

# Check if rc.S files exist.
if [ ! -f ${RC6_STD} ]; then
    echo "File ${RC6_STD} does not exist. Aborting... "
    exit 1
fi
if [ ! -f ${RC6_RAMBOOT} ]; then
    echo "File ${RC6_RAMBOOT} does not exist. Aborting... "
    exit 1
fi

# Check for leftovers from previous runs.
if [ -f ${BOOT}/${SYSIMG} ]; then
    echo "Removing old ${BOOT}/${SYSIMG}... "
    rm ${BOOT}/${SYSIMG}
fi

# Clear logfiles of parent system.
cat /dev/null > ${LOG_PATH}/cron
cat /dev/null > ${LOG_PATH}/debug
cat /dev/null > ${LOG_PATH}/lastlog
cat /dev/null > ${LOG_PATH}/messages
cat /dev/null > ${LOG_PATH}/ntp.log
cat /dev/null > ${LOG_PATH}/secure
cat /dev/null > ${LOG_PATH}/syslog
cat /dev/null > ${LOG_PATH}/wtmp

# Create mountpoint for ramdisk if it does not exist.
if [ ! -d ${RAMDISK} ]; then
    mkdir ${RAMDISK}
    echo "Ramdisk mountpoint ${RAMDISK} created."
fi

echo "Switching fstab to fstab.ramboot... "
ln -sf ${FSTAB_RAMBOOT} /etc/fstab

echo "Switching rc.S to rc.S.ramboot... "
ln -sf ${RC6_RAMBOOT} /etc/rc.d/rc.S

echo "Mounting ramdisk on ${RAMDISK}... "
mount -t tmpfs -o size=${RAMDISK_SIZE} tmpfs ${RAMDISK}

echo "Copying system to ${BOOT}/${SYSIMG} ... "

exec 3>&1
exec 1>/dev/null

cd /
# The --one-file-system option 'x' ask the cp command not 
# to cross mount points and stay in local file system when copying 
# files and directories. So "/sys, /proc, /mnt/ramdisk" will not be copied.

cp -vax /. ${RAMDISK}/.
cp -vax /dev/.  ${RAMDISK}/dev/.
rm  ${RAMDISK}/${SHELLSCRIPT_PATH}

cd  ${RAMDISK}
tar -cf   ${BOOT}/${SYSIMG} ./
cd /

exec 1>&3

echo "Switching fstab and rc.S back to std... "
ln -sf ${FSTAB_STD} /etc/fstab
ln -sf ${RC6_STD} /etc/rc.d/rc.S

echo "Umounting ramdisk... "
umount ${RAMDISK}

echo "done"
exit 0
 

/boot/sysimg.tar erzeugen und Ramdisk Router booten.

# cd /boot
# chmod 0770 create_rtr05_bootimg.sh
# ./create_rtr05_bootimg.sh
# telinit 6
 

19.11 Sicherung des laufenden Systems

Eine Systemsicherung des Ramdisk Routers lässt sich dank der SSD sehr einfach durchführen. Den Router in die Ramdisk booten, anschliessend kann das Grundsystem problemlos auf eine freie Partition − beispielsweise nach /dev/sda6 − oder auf einen USB Stick kopiert werden. Vorgehen:

Grundsystem und freie Partition mounten.

# mount /dev/sda1 /mnt
# mkdir /vol_b
# mount /dev/sda6 /vol_b
 

/mnt/boot/sysimg.tar braucht nur Platz und muss nicht gesichert werden.

# mv /mnt/boot/sysimg.tar /vol_b
 

Wenn der Backup nicht auf der SSD des Routers verbleiben soll, einen USB Stick mounten.

# mount /dev/sdb1 /media/usb
 

System kopieren.

# cd /mnt
# tar -czSpv --numeric-owner --atime-preserve -f /media/usb/slack11_lnxrtr_v05_2019-01-02.tar.gz ./
 

sysimg.tar an seinen Platz zurückkopieren und /dev/sda1 umounten.

# mv /vol_b/sysimg.tar /mnt/boot
# umount /mnt
 

Ausgangszustand wiederherstellen, vol_b wird nicht mehr gebraucht. USB Stick umounten.

# umount /vol_b
# rmdir /vol_b
# umount /media/usb
 

Den Backup im feuer- und erdbebensicheren Panzerschrank verwahren.
;-)

 


Prev Home
IPv6 Router Content That's all folks