Skip to content

Instantly share code, notes, and snippets.

@shakahl
Last active November 4, 2024 00:51
Show Gist options
  • Save shakahl/603df8c393138d17ce8416a2f5f7a5cc to your computer and use it in GitHub Desktop.
Save shakahl/603df8c393138d17ce8416a2f5f7a5cc to your computer and use it in GitHub Desktop.
OpenWrt Hacking

OpenWrt Hacking

Guides

More space for packages with extroot on your OpenWrt router

If you would like to install extra packages on OpenWrt, but you have run out of space on your router’s internal flash memory, then this tutorial is for you.

The plan is to copy the OpenWrt’s root filesystem onto an external USB flash drive, and tell the router to switch to that when it boots up.

All you need is a standard USB flash drive, a USB capable router running OpenWrt, and about 30 mins.

Theory

The OpenWrt wiki pages for this subject are very good. If you’re interested in reading about all the different options, then take a look (for example, it’s possible to mount the USB drive on /opt and install extras here, but some packages expect to be installed in root and won’t behave nicely).

In case you’d like to look it up later, the type of extroot that I’m talking about here is external root (aka pivot root), not external overlay (aka pivot-overlay).

Process

This assumes that you have already formatted your external USB drive with a journaling filesystem (like EXT3 or EXT4). If you haven’t, do this first (the partition managers in Ubuntu and Kubuntu do this very easily, do a google search for a tutorial if you’re unsure how to do this).

To use pivot root, you must be using a version of OpenWrt that is newer than v12 (so 12.09 Attitude Adjustment is fine, but Backfire is not).

First, connect to OpenWrt via ssh or telnet.

Install some packages

First, install the package that will swap your root from the router’s inbuilt flash memory to the external USB flash device:

opkg update
opkg install block-mount
Copy your current root filesystem to the USB flash drive

Before you do this, make sure your router is secure (e.g. SSH login isn’t possible from WAN, wifi interfaces are password protected etc).

This is important because if something goes wrong when your router boots up then OpenWrt will be unable to boot to the USB flash drive, leaving you with whatever your present setup is until you can make it boot to the USB drive properly.

First, install fdisk, a tool to tell you info about attached devices:

opkg update
opkg install fdisk

Now, insert your USB drive and run the following command to get some details about it:

root@OpenWrt:~# fdisk -l
...
Disk /dev/sda: 4229 MB, 4229496832 bytes
255 heads, 63 sectors/track, 514 cylinders, total 8260736 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00933453

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1              63     8257409     4128673+  83  Linux

You see your USB drive listed under “Device”. Now make a mount point for the drive. You can choose whatever you like instead of sda1, just remember what you chose later!

mkdir /mnt/sda1

Mount the drive on the mount point you just created (replace /dev/sda2 with whatever you got from the fdisk command, and /mnt/sda1 with whatever you chose as your mount point):

mount /dev/sda2 /mnt/sda1

Now copy the root filesystem from the router’s inbuilt flash to the USB drive with these commands (if you chose a name other than /mnt/sda1 in the previous step, then replace /mnt/sda1 in line 3):

mkdir -p /tmp/cproot
mount --bind / /tmp/cproot
tar -C /tmp/cproot -cvf - . | tar -C /mnt/sda1 -xf -
umount /tmp/cproot

You now have a USB drive with a copy of your router’s filesystem on it. The next step is to make it automatically mount when you boot up, and use it as root.

Configure /etc/config/fstab

Open /etc/config/fstab with your favourite text editor:

nano /etc/config/fstab

If nano is not installed, you can use vi (which is installed by default, but is horrible!) or you can just install nano with:

opkg update
opkg install nano

Add the following to the file:

config mount
        option target        /
        option device        /dev/sda1
        option fstype        ext3
        option options       rw,sync
        option enabled       1
        option enabled_fsck  0
Reboot and Check

When you reboot, you should now be running OpenWrt from your USB stick.

Check your current mounts with this command:

mount

Output should be something similar to the following:

root@OpenWrt:~# mount
rootfs on / type rootfs (rw)
/dev/root on /rom type squashfs (ro,relatime)
proc on /proc type proc (rw,noatime)
sysfs on /sys type sysfs (rw,noatime)
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noatime,size=63340k)
tmpfs on /dev type tmpfs (rw,noatime,size=512k,mode=755)
devpts on /dev/pts type devpts (rw,noatime,mode=600)
/dev/sda1 on / type ext4 (rw,sync,relatime,user_xattr,barrier=1,data=ordered)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
none on /proc/bus/usb type usbfs (rw,relatime)

See how much space you’ve created for exciting packages with this command:

df -h

Which should show you something like this:

root@OpenWrt:~# df -h
Filesystem                Size      Used Available Use% Mounted on
rootfs                    3.9G    157.1M      3.6G   4% /
/dev/root                 2.0M      2.0M         0 100% /rom
tmpfs                    61.9M    932.0K     60.9M   1% /tmp
tmpfs                   512.0K         0    512.0K   0% /dev
/dev/sda1                 3.9G    157.1M      3.6G   4% / 

You’re all done. Have fun building your personalised OpenWrt cathedral!

OpenWRT on the Netgear WNDR3700

Ever since I obtained the Netgear router, I replaced the OEM firmware with OpenWRT firmware, though it was with the stock image and using the internal storage, which is about 4MB.

I was happy to find that I was able to upgrade the firmware to the latest version, so I installed 18.06.4. I managed to configure it so that it would hand out IP addresses via DHCP, act as a DNS server and resolve the hostnames. I don’t really intend on the router doing much more, to be quite honest, just find that making it do too much doesn’t make sense and may make it more vulnerable.

But I did try to install several packages and ended up filling up the internal storage to 100%, which is not the first time I ran into that issue. So I looked into using the USB port on the router and moving the root to the external storage.

Creating a Custom OpenWRT Firmware

I looked into the documentation from OpenWRT on the Extroot Configuration and created a simple firmware version that contained the necessary tools to mount the USB thumb drive as root.

After downloading the image builder package from the Releases page at OpenWRT, I proceeded to check that my router was still supported by running the following command

make info | grep -A 2 -i 'wndr3700'

Be sure to run that command on the directory that is created when extracting the contents of the image builder archive. The output of that command should look something like this

wndr3700:  
    NETGEAR WNDR3700  
    Packages: kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport kmod-leds-wndr3700-usb

If you are doing this for another router, replace wndr3700 with whatever your router’s model number is.

Now we can proceed to create the base firmware for the router by running the command below

make image PROFILE=wndr3700 PACKAGES="kmod-fs-ext4 kmod-usb-storage kmod-usb-ohci kmod-usb-uhci"

This will take a while to complete, specially when other components need to be downloaded to the system. If all ended successfully, then we should have several .bin files created under bin/targets/ar71xx/generic .

Since I was already running OpenWRT on the router, I used the bin file with sysupgrade in the name. Just upload the firmware through the web interface and reset the router to factory defaults.

Mounting Root in the USB Thumb Drive

Because the firmware I created for the router is the base version, it doesn’t have a web interface, so access is only available via ssh and there is no default password for root, also it is only accessible from the LAN side.

Once we have access to the router, I first proceeded to update the packages and install the block-mount package by running the following commands

opkg update  
opkg install block-mount

Validate that the necessary kernel modules are loaded by running the command

lsmod | grep -Ei 'sd_mod|usb-storage|ext4'

The output should be something along the lines of

crc16                    960  1 ext4  
crypto_hash             8288  3 ext4,jbd2,crc32c_generic  
ext4                  326304  0  
jbd2                   45616  1 ext4  
mbcache                 2768  1 ext4  
scsi_mod               86752  2 usb_storage,sd_mod  
sd_mod                 25424  0

I wanted to make sure that after I made the necessary changes, that they were in fact applied, so I checked the current status of storage by running the df -h command before and after making the changes, being sure to document all of the output.

Since I have a lot of headless devices running in my network, I always want to make sure that they’re able to boot up successfully without user interaction, so I always run through a reboot process after configuring a service or system.

At this point we can mount the USB thumb drive, be sure to format the storage device with ext4 partition type previously as we will not run through that process in the router due to lack of tools. Mount the storage device using the command below

mount /dev/sda1 /mnt

If there are multiple partitions made on the USB thumb drive, then be sure to replace /dev/sda1 accordingly. I’m using an 8GB thumb drive so I only created one partition. Now, 8GB is quite overkill, but I didn’t have any smaller thumb drives, not that they’re easily available anyways.

Once mounted, verify that it is in fact mounted, we need to copy over all of the current data in /overlay to the /mnt directory and we do this by running this command

tar -C /overlay/ -c . -f - | tar -C /mnt/ -xf -

Once this copy process is completed, run the sync command, then unmount the thumb drive with the command umount /dev/sda1 and run the command below to create the fstab for this thumb drive

block detect > /etc/config/fstab

The file that is created should look something like the one below

config 'global'  
       option  anon_swap       '0'  
       option  anon_mount      '0'  
       option  auto_swap       '1'  
       option  auto_mount      '1'  
       option  delay_root      '5'  
       option  check_fs        '0'  


config 'mount'  
       option  target  '/mnt/sda1'  
       option  uuid    '01234567-89AB-CDEF-1234-567890ABCDEF'  
       option  enabled '0'

We need to change it to reflect that this is the new /overlay by changing the target and enabled options to the ones below

config 'mount'  
       option  target  '/overlay'  
       option  uuid    '01234567-89AB-CDEF-1234-567890ABCDEF'  
       option  enabled '1'

Save the file and enable the fstab configuration with the command below

/etc/init.d/fstab enable

At this point reboot the router and wait for it to come back up. There are a couple of steps more that we need to take, but at this point the router should come back up and be using the thumb drive as the primary storage, we can validate this using the df -h command.

We also need to check that uci sees the changes, so run the following command

uci show fstab

If the output comes back like the one below

fstab.@global[0]=global  
fstab.@global[0].anon_swap='0'  
fstab.@global[0].anon_mount='0'  
fstab.@global[0].auto_swap='1'  
fstab.@global[0].auto_mount='1'  
fstab.@global[0].delay_root='5'  
fstab.@global[0].check_fs='0'  
fstab.@mount[0]=mount  
fstab.@mount[0].target='/mnt/sda1'  
fstab.@mount[0].uuid='01234567-89AB-CDEF-1234-567890ABCDEF'  
fstab.@mount[0].enabled='0'

We will need to make some changes by running the two commands below

uci set fstab.@mount[0].target='/overlay'  
uci set fstab.@mount[0].enabled='1'  
uci commit fstab  
service fstab boot

We can reboot the device once more and make sure that the external storage is still being mounted.

Rootfs on External Storage (extroot)

Rootfs on External Storage (extroot) As TurrisOS is a fork of OpenWrt, most of the principles of OpenWrt are applicable to TurrisOS. Extroot is one of them.

What is extroot? Almost every router has a small amount of persistent memory. Turris Omnia has 8 GB of storage but developers say that this storage was not designed to be heavily used for read/write. Sometimes it can be an issue, for example if it is needed to:

Have permanent /var directory instead of symbolic link to /tmp Install more than 8 GB of software but don't want to alter opkg target installation pathes Use software that requires a lot of read/write operations to the root filesystem but don't want to damage the internal memory. There are several workarounds which involve creating symbolic links from the router's internal filesystem to the one which is mounted from USB device. But there is a choice which might be more convenient and reliable in some cases: extroot.

In OpenWrt there is a possibility to replace the root filesystem which is located in the internal memory with the one from external device during the boot. Original instructions for OpenWrt to achieve that can be found here.

How to do extroot on Turris Omnia If you fail, there is a possibility to soft-brick your device, so please do the backups! If you failed and router doesn't boot, please follow these instructions.

USB device is needed, make sure it is working. If it is a hard drive, check that is has enough power from USB port to work and check its cable. At least one partition on the USB device must be empty. One of the partitions will be used for extroot and will be mounted as / (root). Others can be used for any custom mounts including swapping. Extroot only supports Ext4, so if you have a partition of other type, use mkfs.ext4 to re-format the partition. Please stop all non-core activities like torrent client, DLNA server, Samba server etc. Clone the internal filesystem to the external device. For example, if the device appeared as sda1:

mkdir -p /tmp/introot
mkdir -p /tmp/extroot
mount --bind / /tmp/introot
mount /dev/sda1 /tmp/extroot
tar -C /tmp/introot -cvf - . | tar -C /tmp/extroot -xf -
umount /tmp/introot
umount /tmp/extroot

In LuCI, navigate to System → Mount Points → Add. Check Enable this mount. Choose your external USB device from UUID combo box. Choose Use as root filesystem (/) from Mount point combo box. Hit SAVE & APPLY Now configuration should look similar to this:

# cat /etc/config/fstab

config global
        option anon_swap '0'
        option anon_mount '0'
        option auto_swap '1'
        option auto_mount '1'
        option delay_root '5'
        option check_fs '0'

config mount
        option uuid '1f0e8e00-b854-49d2-97ee-4b57bdaccb1d'
        option target '/'
        option enabled '1'

Copy /etc/config/fstab to the external filesystem:

mount /dev/sda1 /tmp/extroot
cp /etc/config/fstab /tmp/extroot/etc/config/fstab
umount /tmp/extroot

Cross the fingers and reboot. After reboot, mounts should look like that:

# mount
/dev/mmcblk0p1 on /rom type btrfs (ro,noatime,ssd,space_cache,commit=X,subvolid=ABC,subvol=/@)
...
/dev/sda1 on / type ext4 (rw,relatime,data=ordered)
...

From now all your data would be stored on the external drive. You can find the internal root filesystem mounted to /rom. Notes I'd recommend to keep essential files like the contents of /etc/config in sync between extroot and internal memory. I cannot say for sure at which exact moment the internal memory is replaced with the external one. It has to be /etc/rc.d/S40fstab, so scripts with level less then 40 have to be loaded from internal memory while the others - from the external storage. Since /rom is obviously is read-only, to copy changed files from the extroot to internal memory, you'd have to remount it for read/write:

mount /rom -o remount,rw

Please be aware that schnapps most probably will stop to work with extroot or will work with errors. It uses Btrfs snapshot feature to work but Brtfs is not supported by extroot. If you can shed some light on that, please update this article. You can now make /var permanent (reboot required):

cp -r /tmp /var-tmp
rm /var
mv /var-tmp /var

Usefull stuff

Extroot

SysUpgrade with extroot overlay

  1. backup your installed packages opkg list-installed | cut -f 1 -d ' ' > /root/installed_packages.txt
  2. Flash normally, keeping settings.
  3. The router will boot with all settings, without the extra packages. Setup internet access if it is not working already.
  4. Install packages to access the usb drive opkg install block-mount kmod-fs-ext4 kmod-usb-storage e2fsprogs kmod-usb-ohci kmod-usb-uhci fdisk
  5. Format the usb drive and copy overlay mount /dev/sda1 /mnt ; tar -C /overlay -cvf - . | tar -C /mnt -xf - ; umount /mnt
  6. Fix fstab and reboot
  7. If all goes well it will boot with overlay of usb as root.
  8. Install extra packages and optionally add old overlay to fstab.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment