R2s Plus Router
I want to run my own network gear. I suppose that’s just because my day job is
writing network software for Linux, and I feel like I should be able to do it.
I’m not great at hardware, but I know a decent bit about using Linux networking,
for moving packets around. And it shouldn’t be much harder than iproute2
and
nftables
, right?
I don’t care too much about speed; I remember dial-up and live in a household of two. Even hitting 100 Mbps would be plenty. So I went cheap and bought a [NanoPi R2S Plus]1, a tiny, Linux-capable SBC with two RJ-45 ports.
Flashing
I really wanted to flash the on-board eMMC module via USB, but I just couldn’t
figure out the right invocation of upgrade_tool
2 or
rkdeveloptool
3 that got the board to boot. And I sunk many
hours into studying their documentation and trying things. It was just too
opaque and outside my expertise. Fortunately, I have a microSD card laying
around, so I used FriendlyElec’s eflasher image instead.
$ gunzip rk3328-eflasher-debian-bookworm-core-6.1-arm64-20231213.img.gz
$ sudo dd if=rk3328-eflasher-debian-bookworm-core-6.1-arm64-20231213.img of=/dev/mmcblk0 bs=4M status=progress
Put the card in the board, plug in the power, and connect to the serial console from my desktop:
$ picocom -b 150_0000 /dev/ttyUSB0
...
Ubuntu 22.04 LTS NanoPi-R2S-Plus ttyS2
Default Login:
Username = pi
Password = pi
NanoPi-R2S-Plus login: pi
Password:
pi@NanoPi-R2S-Plus:~$ head -n1 /etc/os-release
PRETTY_NAME="Ubuntu 22.04.3 LTS"
pi@NanoPi-R2S-Plus:~$ sudo eflasher -i /mnt/sdcard/debian-bookworm-core-arm64/
Using config file: "/tmp/eflasher.conf"
-------------------------------------------------------
>>Debian 12 Core
Ready to Go with Debian,Total size: 1.3 GB,
Installing Debian ..., , ,
Installing Debian, ,Formatting,Done
Installing Debian, ,Formatting,Done
Finish!,Speed: 48 MB/s
RunCmd: "/bin/sh" "-c /usr/bin/sd_monitor" pid: 724
^C
pi@NanoPi-R2S-Plus:~$ poweroff
Remove the SD card and hit the reset button. This time, the serial console shows
Debian GNU/Linux 12 NanoPi-R2S-Plus ttyS2
NanoPi-R2S-Plus login: pi
Password:
Linux NanoPi-R2S-Plus 6.1.63 #218 SMP Thu Nov 30 20:48:04 CST 2023 aarch64
pi@NanoPi-R2S-Plus:~$ head -n1 /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
Perfect.
Configuration
Now on to the part I’m more comfortable with. First, I want the network interfaces to have sane names so they’re easier to refer to as I admin the system.
$ cat <<EOF > /etc/systemd/network/25-lan.link
[Match]
MACAddress=c6:f7:85:65:33:77
Type=ether
[Link]
Name=lan
$ cat <<EOF > /etc/systemd/network/25-wan.link
[Match]
MACAddress=c6:f7:ba:a5:59:5b
Type=ether
[Link]
Name=wan
$ cat <<EOF /etc/systemd/network/75-lan.network
[Match]
Name=lan
[Network]
Address=192.168.0.1/24
$ cat <<EOF /etc/systemd/network/75-wan.network
[Match]
Name=wan
[Network]
DHCP=ipv4
[DHCPv4]
UseDNS=false
Now onto the pieces that make this system a router.
$ cat <<EOF > /etc/sysctl.d/local.conf
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
EOF
$ apt install nftables dnsmasq
$ cat <<EOF > /etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
table inet router {
flowtable f {
hook ingress priority 0
devices = { lan, wan }
counter
}
chain input {
type filter hook input priority filter; policy drop;
iifname "lan" accept
iifname "wan" ct state vmap { established : accept, related : accept, invalid : drop }
counter accept
}
chain output {
type filter hook output priority filter; policy drop;
oifname "lan" accept
udp dport 53 counter accept comment "dns"
udp sport 123 udp dport 123 counter accept comment "ntp"
ip daddr 8.45.176.225-8.45.176.232 tcp dport { 80, 443 } counter accept comment "mirrors.aliyun.com"
counter accept
}
chain prerouting {
type filter hook prerouting priority filter; policy drop;
iifname "lan" accept
iifname "wan" ct state established,related accept
}
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname "wan" masquerade
}
}
EOF
$ cat <<EOF > /etc/dnsmasq.d/lan.conf
# Run DNS server on LAN IP
listen-address=127.0.0.1,192.168.0.1
cache-size=1000
no-resolv
domain-needed
server=1.1.1.1
local=/lan/
domain=lan
expand-hosts
# Only listen to routers' LAN NIC. Doing so opens up tcp/udp port 53 to localhost and udp port 67 to world:
interface=wan
bind-interfaces
dhcp-lease-max=100
# Set default gateway
dhcp-option=3,192.168.0.1
# Set DNS servers to announce
dhcp-option=6,192.168.0.1
# If your dnsmasq server is also doing the routing for your network, you can use option 121 to push a static route out.
dhcp-option=121,0.0.0.0/24,192.168.0.1
# Dynamic range of IPs to make available to LAN PC and the lease time.
# The range of addresses here must lie within the address range assigned to the virtual interface.
dhcp-range=192.168.0.2,192.168.0.200,1h
EOF
These two services and their configuration files turn my new little box into a functional home router.
https://speed.cloudflare.com/ says I’m getting around 90 Mbps, which is good enough for me. I don’t even pay for much more than that. The devices on my desk are wired up like this:
Totally worth the $50.