From b8e49835b17df8273092ca72543442bdddc7354d Mon Sep 17 00:00:00 2001 From: Alex Tomic Date: Mon, 12 Aug 2024 16:01:06 -0400 Subject: [PATCH] ms8.2 - usability and documentation improvements * Revamp documentation to reflect somewhat easier installation process using new single-binary builds * Add strategy target for rockchip64 devices so we're not dependent on older kernel builds from the armbian-btf-kernel repo * Clean up unneeded dependences from image build and set up most items to run on reboot automatically * Small issue fixes here and there --- .github/workflows/build-btf-kernel.yml | 8 +- Makefile | 2 +- README.md | 8 +- cmd/nethadone.go | 12 +- config/nethadone.yml | 2 +- doc/install.md | 180 ++++++++++++------------- scripts/build.sh | 47 +++++-- scripts/customize-image.sh | 61 ++------- 8 files changed, 150 insertions(+), 170 deletions(-) diff --git a/.github/workflows/build-btf-kernel.yml b/.github/workflows/build-btf-kernel.yml index 833d907..24fe700 100644 --- a/.github/workflows/build-btf-kernel.yml +++ b/.github/workflows/build-btf-kernel.yml @@ -34,10 +34,10 @@ jobs: - boardfamily: sunxi branch: legacy representative: orangepi-r1 - # TODO Enable for R1plus and others as needed - # - boardfamily: rockchip64 - # branch: current - # representative: rockpro64 + # TODO Enable for others as needed + - boardfamily: rockchip64 + branch: legacy + representative: orangepi-r1plus fail-fast: false env: BOARD_FAMILY: ${{ matrix.boardfamily }} diff --git a/Makefile b/Makefile index 3064f2c..cbb7a43 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ run-root: all: GOARCH=arm GOOS=linux go build -o build/nethadone-arm-linux ./cmd/nethadone.go GOARCH=arm64 GOOS=linux go build -o build/nethadone-arm64-linux ./cmd/nethadone.go - GOARCH=amd64 GOOS=linux go build -o build/nethadone-arm-linux ./cmd/nethadone.go + GOARCH=amd64 GOOS=linux go build -o build/nethadone-amd64-linux ./cmd/nethadone.go build: go build ./cmd/nethadone.go diff --git a/README.md b/README.md index 4816d5b..388ef1f 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,11 @@ etc.) while avoiding the downsides of excessive use. Nethadone is in active development and has been tested on the following devices: -* [Orange Pi R1 Plus](http://www.orangepi.org/orangepiwiki/index.php/Orange_Pi_R1_Plus) -* [Orange Pi R1](http://www.orangepi.org/orangepiwiki/index.php/Orange_Pi_R1) +* [Orange Pi R1 Plus](http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/orange-pi-R1-Plus.html) +* [Orange Pi R1](http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-R1.html) +* [Orange Pi Zero](http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-Zero-LTS.html) -Any similar device using an armv7 or arm64 chipset should work. -Please check out [doc/install.md](doc/install.md) for details. +Please check out [doc/install.md](doc/install.md) for more details. For development or testing on a local VM, please see [doc/development.md](doc/development.md) diff --git a/cmd/nethadone.go b/cmd/nethadone.go index 31102a3..6b7b867 100644 --- a/cmd/nethadone.go +++ b/cmd/nethadone.go @@ -19,16 +19,20 @@ import ( func main() { - wanIf := flag.String("wan-interface", "eth0", "Interface connecting out to internet") - lanIf := flag.String("lan-interface", "eth1", "Interface connected to local network") + wanIf := flag.String("wan-interface", "", "Interface connecting out to internet") + lanIf := flag.String("lan-interface", "", "Interface connected to local network") configFile := flag.String("config-file", "nethadone.yml", "Configuration file") flag.Parse() config.ParseConfig(*configFile) // Command line parameters override anything that might be in the config - config.Cfg.LanInterface = *lanIf - config.Cfg.WanInterface = *wanIf + if *lanIf != "" { + config.Cfg.LanInterface = *lanIf + } + if *wanIf != "" { + config.Cfg.WanInterface = *wanIf + } log.Println("Configuration: ", repr.String(config.Cfg, repr.Indent(" "))) database.Connect() diff --git a/config/nethadone.yml b/config/nethadone.yml index 8ed723e..e6c44cb 100644 --- a/config/nethadone.yml +++ b/config/nethadone.yml @@ -1,7 +1,7 @@ # The WAN interface should have access to the internet wan_interface: "eth0" # The LAN interface is where your local devices are -lan_nterface: "eth1" +lan_interface: "eth1" cfg_db: "/root/cfg.db" dns_db: "/root/dns.db" diff --git a/doc/install.md b/doc/install.md index fe6f2da..f4e853e 100644 --- a/doc/install.md +++ b/doc/install.md @@ -1,101 +1,109 @@ # Installation -Nethadone still, unfortunately, requires a lot of manual steps to -get working. -It is a priority to make this installation process less cumbersome, -but anyone brave enough to attempt this in its current state -has my infinite gratitude! +## Requirements -## Requirements +Nethadone has been tested on the latest Ubuntu Noble-based versions of +Armbian (24.04 or 24.08). You can download an image for your board at +the [Armbian download page](https://www.armbian.com/download/?tx_maker=xunlong). -### Hardware -Nethadone has been tested on: +## Image prep -* VMWare-based VM (for development) -* Orange Pi R1Plus / R1Plus LTS - * 64-bit Rockchip RK3328 - * 1GB RAM - * 2x GBit ethernet - * Wifi (not functional w/ Armbian yet) -* Orange Pi R1 - * 32-bit Allwinner H3 - * 2 x 100Mbit ethernet - * Wifi (working) - * 256MB / 512MB RAM +The contents of `scripts/customize-image.sh` will need to be run, +as root, in a fresh installation of the image you downloaded. +If you want to save time, you can prep using the chroot build +script, eg: -In theory, any device with two network interfaces should work, but I have not had a chance to test others. +```bash +cd scripts +./build.sh -i /tmp/Armbian_community_24.8.0-trunk.554_Orangepizero_noble_current_6.6.43.img -m ~/mnt -a arm +``` -An SD card 16GB or greater is recommended. +`build.sh` makes liberal use of `sudo` so you may want to run this +on a VM or cloud server with a fast link. -### OS +Replace the `-i` and `-m` options with wherever you uncompressed the +Armbian image above, and an empty folder to use for a mount point. +The `-a` option indicates whether you are building for an arm64 +or armv7 image. + +> [!TIP] +> `build.sh` is just a chroot wrapper that pre-installs everything +required for nethadone to run. If you prefer to do the installation +of required packages directly on the SBC, you can copy paste from +`customize-image.sh` after you have flashed the stock image using +[Balena etcher](https://etcher.balena.io/) or whichever flashing tool you prefer. -Ubuntu-based 22.04 LTS or derivative (eg. Armbian 23.8) -Ubuntu 22.04 or 24.04 LTS and derivatives (i.e. Armbian) are working -Other OS versions may work, but the further away from Linux -6.1 (either newer or older), the more likely eBPF -issues may be encountered. +At a high level, the `customize-image.sh` script: -## OS Setup - Orange Pi R1+ (Arm64) +* Installs and configures compiler dependencies, bpftool and prometheus +* Creates a systemd service for nethadone to run on boot +* Downloads and installs a BTF-enabled kernel +* Downloads the nethadone binary from Github -> [!NOTE] -> I am in the process of streamlining this installation process, -> first for the armv7 Orange Pi R1 and eventually for the R1+. -### Base image -For the Orange Pi R1+, you need to get the Armbian 23.8.1 Jammy build: +## Nethadone post-installation -https://xogium.performanceservers.nl/archive/orangepi-r1plus/archive/Armbian_23.8.1_Orangepi-r1plus_jammy_current_6.1.50.img.xz +The easiest way to test out Nethadone is with a board like the +Zero or R1 that has functional wifi with Armbian. You can spin +up a [hotspot](https://ubuntu.com/core/docs/networkmanager/configure-wifi-access-points) with `nmcli`, eg: -This is because we will need to use a BTF-enabled kernel provided -by [daeuniverse](https://github.com/daeuniverse/armbian-btf-kernel), -and that is the latest version of Armbian provided there. +```bash +sudo nmcli dev wifi hotspot ifname wlan0 ssid nethadone password $password channel 8 band bg +``` -### Image prep +The network-manager hotspot conveniently sets up a LAN for you +for any devices that connect wirelessly (default seems to be `10.42.0.0/24`), and NAT out to your wired interface, which should be plugged in +directly to your primary router. -The contents of `scripts/customize-image.sh` will need to be run, -as root, in a fresh installation of the image you downlaoded. -If you want to save time, you can prep this on your machine using -the chroot build script, eg: +> [!NOTE] +> The network-manager hotspot also has the advantage of setting up DNS +> caching automatically with `dnsmasq`. This makes it easier for +> nethadone to capture these packets, as clients receiving a local +> IP as a DNS server in DHCP configuration typically do not use DNS-over-HTTPS. -```bash -cd scripts -./build.sh -i /tmp/Armbian_23.8.1_Orangepi-r1plus_jammy_current_6.1.50.img -m ~/mnt -``` +You can drop the `nmcli` command you used into `/etc/rc.local` to have +it start up on reboot. -Replace the `-i` and `-m` options with wherever you uncompressed the -Armbian image above, and an empty folder to use for a mount point. +### Adjusting cofiguration -`build.sh` is just a chroot wrapper that pre-installs everything -required for nethadone to run; if you prefer to do the installation -of required packages directly, you can copy paste from -`customize-image.sh` after you have flashed the base image using -[Balena etcher](https://etcher.balena.io/) or whichever flashing tool you prefer. +If you want to customize any parameters, or have different interface +names, you can create a `/etc/nethadone.yml` file. +See the sample [config](../config/nethadone.yml) for more details. -### Nethadone installation +## Wired-only Deployment -Once you have the image flashed and the device booted, at this -point you should be ready to install Nethadone. +Faster devices like the OrangePi R1+, as of my last tests, do not have +functional wifi with stock Armbian. This means they need to be introduced +between your wifi router and your device providing internet access using +the two ethernet ports. -First clone the repo as regular user (but one with sudo privilege) +This provides fast, full coverage for all devices in your home, but could take down your internet in the event of an issue with nethadone. +As this is still very much in development, it's recommended to stick +with a secondary access point for now. -```bash -git clone https://github.com/atomic77/nethadone -``` +If you have access to an extra wifi router, this is an example of how +you can still make use of a wired-only device: -The default configuration file should work on an r1plus, and you -can run this to build and launch: +![Secondary network](nethadone-secondary-network.drawio.png) + +In such as case, you will need to set up NAT for the interface +connected to the , eg. if `eth0` is your wan interface: ```bash -make run-root +iptables -t nat -A POSTROUTING -o end0 -j MASQUERADE ``` +*TODO - properly document other steps required for this scenario* + +## Runtime logs If all goes well and nethadone is routing and inspecting traffic, -you should see log entries like: +you should see be able to see log entries like: ```bash +$ journalctl -u nethadone.service --follow ... 2024/07/20 15:48:58 Registering prometheus metrics 2024/07/20 15:48:58 Setting up SimpleLoadAverage policy @@ -161,7 +169,7 @@ There is a basic admin interface where you can configure glob groups, see the currently active policy and inspect currently mapped DNS to IP addresses, it will be running at: -http://r1plus.local:3000/ +http://orangepi-r1.local:3000/ mDNS is configured by default - if this address does not resolve on your network, replace `r1plus.local` with whatever IP address @@ -183,37 +191,15 @@ are being collected there using similar queries used by nethadone: ![prometheus](prometheus.png) -### Routing Configuration & Client setup - -One of the design goals of Nethadone is to introduce minimal or -no client configuration beyond DHCP. The growing use of DNS over -HTTPS (DoH), unfortunately complicates this, as it prevents -Nethadone from using the typical UDP DNS packets to associate -a client-requested domain with an IP address. - -In practice, the best way to work around this is to install -[pi-hole](https://github.com/pi-hole/pi-hole) -on the same device. Most client devices on your network, if provided -a local DNS server in the DHCP configuration, will automatically -switch to UDP-based DNS, and Nethadone will be able to inspect these -packets. Installing pi-hole on a non-raspberry pi is -straight-forward though not officially supported, I have created a -[youtube video with instructions](https://www.youtube.com/watch?v=m-mIglWyFcs) for installation on an orangepi zero that should work fine against a R1plus. - -Alternatively, you can configure browsers to -[disable the use of DoH](https://www.expressvpn.com/support/troubleshooting/disable-dns-over-https/). - - -## Deployment - -The recommended way of starting out with Nethadone is to create -a separate, 'protected' network, potentially using a old -spare wifi router. This is how it looks in my environment: - -![Secondary network](nethadone-secondary-network.drawio.png) +## Other boards -Ideally, the wifi found on a board like the Orange Pi R1+ could -be used directly to create an isolated netwrk, but as of this time, Armbian does not have good support for the hardware. +Armbian does not ship with BTF-enabled kernels out of the box at this +time; the two kernel builds available for Armbian `BOARDFAMILY` +[`rockchip64`](https://github.com/armbian/build/blob/752ba047b3cb600095f981cbabb8be53d12bb9a2/config/boards/orangepi-r1plus.csc#L3) +and [`sunxi`](https://github.com/armbian/build/blob/752ba047b3cb600095f981cbabb8be53d12bb9a2/config/boards/orangepi-r1.csc#L3), are targeted for the Orange Pi R1 Plus +and R1 and Zero respectively. Others with the same family are likely, +but not certain to work. -If you are confident that your setup is good, you can then introduce Nethadone in between your primary access point and -your cable/DSL/fiber provider. +If you are interested in trying out another board and are having +trouble getting a BTF kernel working, please raise an issue and I'll +try adding it to the Github Action. \ No newline at end of file diff --git a/scripts/build.sh b/scripts/build.sh index e9c86a9..b886cfb 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -9,16 +9,33 @@ usage() { echo "Usage: $0 -i -m " echo "" + echo "This script will mount the provided image into the mount point and run" + echo "customize-image.sh on it. If you have downloaded an .xz file from the Armbian" + echo "site it's a good idea to keep the original compressed copy and uncompress the" + echo "image into /dev/shm if you have the memory" + echo "" echo "Options:" - echo " -i Armbian base image file (uncompressed)" - echo " -m Mount point" + echo " -i Armbian base image file to write into (uncompressed)" + echo " -m Mount location to use for chroot " + echo " -a 'aarch64' for orangepi R1+ and similar, 'arm' for opizero/r1, and similar" exit 1 } +cleanup () { +echo "Cleaning up.." + sudo umount ${mnt}/dev + sudo umount --lazy ${mnt} + sudo e2fsck -p -f ${loop}p1 + sudo losetup -d ${loop} +} + +trap cleanup ERR EXIT + img="" mnt="" +arch="" -while getopts ":i:m:" opt; do +while getopts ":i:m:a:" opt; do case $opt in i) img="$OPTARG" @@ -26,6 +43,9 @@ while getopts ":i:m:" opt; do m) mnt="$OPTARG" ;; + a) + arch="$OPTARG" + ;; \?) echo "Invalid option: -$OPTARG" >&2 usage @@ -37,13 +57,14 @@ while getopts ":i:m:" opt; do esac done -if [ -z "$img" ] || [ -z "$mnt" ]; then - echo "Error: Both -i and -m options are required." +if [ -z "$img" ] || [ -z "$mnt" ] || [ -z "$arch" ]; then + echo "Error: All flags are required." usage fi set -e +# After trimming down the image see if we can reduce this to 3 or 2g truncate -s 4G $img loop=$(sudo losetup --partscan --show --nooverlap -f $img) # This may fail on older versions of growpart and require @@ -62,13 +83,15 @@ sudo mount --bind /dev ${mnt}/dev sudo mkdir ${mnt}/tmp/overlay # To enter into chroot w/ arm64 emulation -sudo cp /usr/bin/qemu-aarch64-static ${mnt}/usr/bin/ +sudo cp /usr/bin/qemu-${arch}-static ${mnt}/usr/bin/ sudo cp customize-image.sh ${mnt}/tmp/ + +# Ubuntu Noble images have a symlink to /run/systemd/resolve/stub-resolv.conf which +# breaks DNS when in chroot. Swap out the current users' resolv.conf so we can +# install packages while in chroot +sudo mv ${mnt}/etc/resolv.conf ${mnt}/etc/resolv.conf.tmp +sudo cp -L /etc/resolv.conf ${mnt}/etc/ sudo chmod +x ${mnt}/tmp/customize-image.sh -# https://stackoverflow.com/questions/8157931/bash-executing-commands-from-within-a-chroot-and-switch-user#8157973 -sudo chroot ${mnt} qemu-aarch64-static /bin/bash -c "/tmp/customize-image.sh" +sudo chroot ${mnt} qemu-${arch}-static /bin/bash -c "/tmp/customize-image.sh" -# Clean up -sudo umount ${mnt} -sudo e2fsck -p -f ${loop}p1 -sudo losetup -d ${loop} +sudo mv -f ${mnt}/etc/resolv.conf.tmp ${mnt}/etc/resolv.conf diff --git a/scripts/customize-image.sh b/scripts/customize-image.sh index ae9550d..59a8bd2 100644 --- a/scripts/customize-image.sh +++ b/scripts/customize-image.sh @@ -2,18 +2,17 @@ case "$(arch)" in 'aarch64') - prom_url='https://github.com/prometheus/prometheus/releases/download/v2.53.1/prometheus-2.53.1.linux-arm64.tar.gz' - go_url='https://go.dev/dl/go1.22.3.linux-arm64.tar.gz' - kern_url='https://github.com/daeuniverse/armbian-btf-kernel/releases/download/main-2023-06-17/kernel-rockchip64-current_23.08.0-trunk--6.1.34-Sca87-Dbeb1-Pa401-C3053Hfe66-HK01ba-Vc222-B76dc.tar' + # kern_url='https://github.com/daeuniverse/armbian-btf-kernel/releases/download/main-2023-06-17/kernel-rockchip64-current_23.08.0-trunk--6.1.34-Sca87-Dbeb1-Pa401-C3053Hfe66-HK01ba-Vc222-B76dc.tar' + kern_url='https://github.com/atomic77/nethadone/releases/download/btf-kernel/kernel-legacy-rockchip64-orangepi-r1plus.tar.gz' + neth_url='https://github.com/atomic77/nethadone/releases/download/nethadone-2024-08-12/nethadone-arm64-linux' ;; 'armv7l') - prom_url='https://github.com/prometheus/prometheus/releases/download/v2.53.1/prometheus-2.53.1.linux-armv7.tar.gz' - go_url='https://go.dev/dl/go1.22.3.linux-armv6l.tar.gz' kern_url='https://github.com/atomic77/nethadone/releases/download/btf-kernel/kernel-legacy-sunxi-orangepi-r1.tar.gz' + neth_url='https://github.com/atomic77/nethadone/releases/download/nethadone-2024-08-12/nethadone-arm-linux' ;; 'x86_64') - prom_url='https://github.com/prometheus/prometheus/releases/download/v2.53.1/prometheus-2.53.1.linux-amd64.tar.gz' - go_url='https://go.dev/dl/go1.22.3.linux-arm64.tar.gz' + neth_url='https://github.com/atomic77/nethadone/releases/download/nethadone-2024-08-12/nethadone-amd64-linux' + ;; # Most x86_64 builds for virtual machine testing use should have BTF enabled '*') echo "Unsupported architecture $(arch), exiting." @@ -26,48 +25,15 @@ apt-get update -y apt-get install -y apt-transport-https ca-certificates curl clang llvm jq \ libelf-dev libpcap-dev libbfd-dev binutils-dev build-essential make \ - vim libbpf-dev avahi-daemon linux-tools-common dnsmasq - -wget ${go_url} -rm -rf /usr/local/go && tar -C /usr/local -xzf go1.* -rm go*.tar.gz -echo "export PATH=\$PATH:/usr/local/go/bin" >> /etc/profile - -##### -# Local prometheus for metrics collection -wget ${prom_url} -tar -C /usr/local/bin --strip-components 1 -xzf prometheus-*.tar.gz -rm prometheus-*.tar.gz - -cp /usr/local/bin/prometheus.yml /etc -mkdir -p /var/lib/prometheus + vim libbpf-dev avahi-daemon linux-tools-common dnsmasq prometheus -cat >> /etc/prometheus.yml << EOF +cat >> /etc/prometheus/prometheus.yml << EOF - job_name: "nethadone" static_configs: - targets: ["localhost:3000"] EOF -cat < /etc/systemd/system/prometheus.service -[Unit] -Description=Prometheus -Wants=network-online.target -After=network-online.target -[Service] -User=root -Restart=on-failure - -ExecStart=/usr/local/bin/prometheus \ - --config.file=/etc/prometheus.yml \ - --storage.tsdb.path=/var/lib/prometheus - -[Install] -WantedBy=multi-user.target - -EOF - -## FIXME The interfaces are not being read from config file due to a bug in nethadone.go cat < /etc/systemd/system/nethadone.service [Unit] Description=Nethadone @@ -87,7 +53,7 @@ WantedBy=multi-user.target EOF systemctl daemon-reload -systemctl enable prometheus +systemctl enable nethadone ###### # NAT forwarding will need to be in place for routing to work, @@ -105,7 +71,7 @@ echo "net.ipv4.ip_forward = 1" > /etc/sysctl.d/20-nethadone.conf # ##### -# Grab the custom BTF-enabled kernel from daeuniverse' repo +# Grab the custom BTF-enabled kernel if [ $(arch) != 'x86_64' ]; then wget ${kern_url} tar xvf kernel-* @@ -113,7 +79,7 @@ if [ $(arch) != 'x86_64' ]; then rm kernel*.tar fi -if [ $(arch) == 'armv7' ]; then +if [ $(arch) == 'armv7l' ]; then apt-get install libc6-dev-armel-cross -y fi @@ -126,6 +92,7 @@ make -j 4 make install rm -rf ~/src -# TODO - Copy in pre-built nethadone binary from github to avoid git +# Finally, copy in pre-built nethadone binary from github to avoid git # checkout and golang compiler - +curl -L -o /usr/local/bin/nethadone ${neth_url} +chmod +x /usr/local/bin/nethadone