commit
e9d5e789f4
|
@ -0,0 +1,12 @@
|
|||
FROM scratch
|
||||
COPY . .
|
||||
ARG ROOT_PW
|
||||
RUN echo -e "${ROOT_PW}\n${ROOT_PW}" | passwd
|
||||
RUN mkdir -p /var/lock
|
||||
RUN opkg update && \
|
||||
opkg install \
|
||||
iperf3 \
|
||||
ip-full && \
|
||||
opkg list-upgradable | awk '{print $1}' | xargs opkg upgrade
|
||||
|
||||
CMD [ "/sbin/init" ]
|
12
Makefile
12
Makefile
|
@ -1,13 +1,17 @@
|
|||
.PHONY: build run clean install uninstall
|
||||
.PHONY: build build-rpi run clean install uninstall
|
||||
|
||||
include openwrt.conf
|
||||
export
|
||||
|
||||
build:
|
||||
@docker build \
|
||||
--build-arg ROOT_PW=${ROOT_PW} \
|
||||
--build-arg OPENWRT_TAG=${OPENWRT_TAG} \
|
||||
docker build \
|
||||
--build-arg ROOT_PW \
|
||||
--build-arg OPENWRT_TAG \
|
||||
-t ${BUILD_TAG} .
|
||||
|
||||
build-rpi:
|
||||
./build-rpi.sh ${RPI_SOURCE_IMG}
|
||||
|
||||
run:
|
||||
./run.sh
|
||||
|
||||
|
|
14
README.md
14
README.md
|
@ -1,8 +1,8 @@
|
|||
# OpenWRT in Docker
|
||||
# OpenWrt in Docker
|
||||
|
||||
Inspired by other projects that run `hostapd` in a Docker container. This goes one step further and boots a full network OS intended for embedded devices called [OpenWRT](https://openwrt.org/), so you can manage all aspects of your network from a user-friendly web UI.
|
||||
Inspired by other projects that run `hostapd` in a Docker container. This goes one step further and boots a full network OS intended for embedded devices called [OpenWrt](https://openwrt.org/), so you can manage all aspects of your network from a user-friendly web UI.
|
||||
|
||||
I only tested this on x86_64, but it might work on ARM too with some minor tweaking.
|
||||
For Raspberry Pi-specific build instructions, see [Building on Raspberry Pi](./rpi.md).
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
@ -17,13 +17,13 @@ I only tested this on x86_64, but it might work on ARM too with some minor tweak
|
|||
```
|
||||
$ make build
|
||||
```
|
||||
If you want additional OpenWRT packages to be present in the base image, add them to the Dockerfile. Otherwise you can install them with `opkg` after bringing up the container.
|
||||
If you want additional OpenWrt packages to be present in the base image, add them to the Dockerfile. Otherwise you can install them with `opkg` after bringing up the container.
|
||||
|
||||
A searchable package list is available on [openwrt.org](https://openwrt.org/packages/table/start).
|
||||
|
||||
## Configure
|
||||
|
||||
Initial configuration is performed using a config file, `openwrt.conf`. Values read from this file at runtime are used to generate OpenWRT format config files.
|
||||
Initial configuration is performed using a config file, `openwrt.conf`. Values read from this file at runtime are used to generate OpenWrt format config files.
|
||||
|
||||
To add or change the base configuration, modify the config templates in `etc/config/<section>.tpl`.
|
||||
|
||||
|
@ -58,10 +58,8 @@ This will delete the container and all associated Docker networks so you can sta
|
|||
|
||||
### Hairpinning
|
||||
|
||||
This took a couple of tries to get working. The most challenging issue was getting traffic from WLAN clients to reach each other.
|
||||
|
||||
In order for this to work, OpenWRT bridges all interfaces in the LAN zone and sets hairpin mode (aka [reflective relay](https://lwn.net/Articles/347344/)) on the WLAN interface, meaning packets arriving on that interface can be 'reflected' back out through the same interface.
|
||||
OpenWRT is not able to set this mode from inside the container even with `NET_ADMIN` capabilities, so this must be done from the host.
|
||||
In order for WLAN clients to see one another, OpenWrt bridges all interfaces in the LAN zone and sets hairpin mode (aka [reflective relay](https://lwn.net/Articles/347344/)) on the WLAN interface, meaning packets arriving on that interface can be 'reflected' back out through the same interface.
|
||||
|
||||
`run.sh` tries to handle this, and prints a warning if it fails.
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Extracts the rootfs from OpenWRT Raspberry Pi image available from
|
||||
# https://downloads.openwrt.org/releases/19.07.2/targets/brcm2708/bcm2708/
|
||||
# and builds a Docker container out of it
|
||||
#
|
||||
# Refer to https://openwrt.org/toh/raspberry_pi_foundation/raspberry_pi
|
||||
# to choose the right image
|
||||
#
|
||||
# If building on x86, you must have qemu-arm and binfmt-support installed
|
||||
set -e
|
||||
|
||||
IMG=${1:-'x'}
|
||||
|
||||
|
||||
mount_rootfs() {
|
||||
echo "* mounting image"
|
||||
offset=$(sfdisk -d ${IMG} | grep "${IMG}2" | sed -E 's/.*start=\s+([0-9]+).*/\1/g')
|
||||
tmpdir=$(mktemp -u -p .)
|
||||
mkdir -p "${tmpdir}"
|
||||
sudo mount -o loop,offset=$((512 * $offset)) -t ext4 ${IMG} ${tmpdir}
|
||||
}
|
||||
|
||||
docker_build() {
|
||||
echo "* building Docker image"
|
||||
sudo docker build \
|
||||
--build-arg ROOT_PW="${ROOT_PW}" \
|
||||
-t ${BUILD_TAG} -f Dockerfile.rpi ${tmpdir}
|
||||
}
|
||||
|
||||
|
||||
cleanup() {
|
||||
echo "* cleaning up"
|
||||
sudo umount ${tmpdir}
|
||||
rm -rf ${tmpdir}
|
||||
}
|
||||
|
||||
test -f ${IMG} || { echo 'no image file found'; exit 1; }
|
||||
trap cleanup EXIT
|
||||
mount_rootfs
|
||||
docker_build
|
|
@ -1,24 +1,31 @@
|
|||
### Sample OpenWRT config file ###
|
||||
|
||||
# general
|
||||
## general
|
||||
# source image for Raspberry Pi build target
|
||||
SOURCE_IMG=openwrt-19.07.2-brcm2708-bcm2708-rpi-ext4-factory.img
|
||||
# source tag for build (x86) target
|
||||
OPENWRT_TAG=x86-64-19.07.2
|
||||
# final tag for built Docker image
|
||||
BUILD_TAG=openwrt
|
||||
# container name
|
||||
CONTAINER=openwrt_1
|
||||
ROOT_PW=changeme123
|
||||
|
||||
# docker network settings
|
||||
# wan
|
||||
WAN_NAME=openwrt-wan
|
||||
WAN_PARENT=enp0s20f0u4
|
||||
# host interface which will provide the WAN link for OpenWRT
|
||||
WAN_PARENT=eth0
|
||||
UPSTREAM_DNS_SERVER=8.8.8.8
|
||||
|
||||
# lan
|
||||
# Static IP address configuration for OpenWRT LAN
|
||||
LAN_NAME=openwrt-lan
|
||||
LAN_DOMAIN=home
|
||||
LAN_SUBNET=192.168.16.0/24
|
||||
LAN6_SUBNET=fd99:1234::/48
|
||||
# Set LAN_ADDR to something other than the first available address
|
||||
# in the subnet - Docker will claim this address for the host
|
||||
LAN_ADDR=192.168.16.2
|
||||
LAN_HOST=192.168.16.1
|
||||
# openwrt doesn't accept CIDR notation; must match LAN_SUBNET
|
||||
LAN_NETMASK=255.255.255.0
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
# Building on Raspberry Pi
|
||||
|
||||
Turn your Pi into a pretty okay-ish travel router (or a very slow main router)!
|
||||
|
||||
OpenWrt officially supports Raspberry Pi hardware if you want to run it as your OS. But running in a container brings many advantages, one of which is not having to re-flash your SD card.
|
||||
|
||||
This has been tested on a Raspberry Pi Zero W running Raspbian Lite, but should work for other versions too. Just make sure you download the right image for your Pi version (refer to the notes in [build-rpi.sh](./build-rpi.sh)).
|
||||
|
||||
|
||||
## IPv6
|
||||
By default Raspbian does not load the kernel module for IPv6 `iptables` on boot.
|
||||
|
||||
Run `sudo modprobe ip6_tables` to load it immediately.
|
||||
|
||||
To persist on reboot, run
|
||||
|
||||
$ echo 'ip6_tables' | sudo tee /etc/modules-load.d/ip6-tables.conf
|
||||
|
||||
---
|
||||
## Build
|
||||
You can build the OpenWRT docker image on the Pi itself, or on your x86 PC with `qemu-arm` installed.
|
||||
|
||||
First download and extract the OpenWRT factory image for your Pi. Refer to the [OpenWrt Table of Hardware](https://openwrt.org/toh/raspberry_pi_foundation/raspberry_pi) to choose the right image. Then run the `make` target.
|
||||
|
||||
The variable `RPI_SOURCE_IMG` can be specified in openwrt.conf or on the command line:
|
||||
```
|
||||
$ https://downloads.openwrt.org/releases/19.07.2/targets/brcm2708/bcm2708/openwrt-19.07.2-brcm2708-bcm2708-rpi-ext4-factory.img.gz
|
||||
$ gzip -d openwrt-*.img.gz
|
||||
$ make build-rpi RPI_SOURCE_IMG=openwrt-19.07.2-brcm2708-bcm2708-rpi-ext4-factory.img
|
||||
```
|
||||
|
||||
If you built the image on your PC, send it to your Raspberry Pi (`$BUILD_TAG` is a config variable):
|
||||
```
|
||||
$ docker save $BUILD_TAG | ssh <your_raspberry_pi_host> docker load
|
20
run.sh
20
run.sh
|
@ -69,7 +69,7 @@ function _set_hairpin() {
|
|||
for i in {1..10}; do
|
||||
echo -n '.'
|
||||
sudo ip netns exec $CONTAINER ip link set $WIFI_IFACE type bridge_slave hairpin on 2>/dev/null && { echo 'ok'; break; }
|
||||
sleep 1
|
||||
sleep 3
|
||||
done
|
||||
if [[ $i -ge 10 ]]; then
|
||||
echo -e "\ncouldn't set hairpin mode, wifi clients will probably be unable to talk to each other"
|
||||
|
@ -78,8 +78,8 @@ function _set_hairpin() {
|
|||
|
||||
function _create_or_start_container() {
|
||||
docker inspect $BUILD_TAG >/dev/null 2>&1 || { echo "no image '$BUILD_TAG' found, did you forget to run 'make build'?"; exit 1; }
|
||||
docker inspect $CONTAINER >/dev/null 2>&1
|
||||
if [[ $? -eq 0 ]]; then
|
||||
|
||||
if docker inspect $CONTAINER >/dev/null 2>&1; then
|
||||
echo "* starting container '$CONTAINER'"
|
||||
docker start $CONTAINER
|
||||
else
|
||||
|
@ -103,9 +103,20 @@ function _create_or_start_container() {
|
|||
fi
|
||||
}
|
||||
|
||||
function _reload_fw() {
|
||||
echo "* reloading firewall rules"
|
||||
docker exec -it $CONTAINER sh -c '
|
||||
for iptables in iptables ip6tables; do
|
||||
for table in filter nat mangle; do
|
||||
$iptables -t $table -F
|
||||
done
|
||||
done
|
||||
/sbin/fw3 -q restart'
|
||||
}
|
||||
|
||||
function main() {
|
||||
test -z $WIFI_IFACE && _usage
|
||||
cd $SCRIPT_DIR
|
||||
cd "${SCRIPT_DIR}"
|
||||
_get_phy_from_dev
|
||||
_nmcli
|
||||
_create_or_start_container
|
||||
|
@ -124,6 +135,7 @@ function main() {
|
|||
echo "* getting address via DHCP"
|
||||
sudo dhcpcd -q "br-${LAN_ID:0:12}"
|
||||
|
||||
_reload_fw
|
||||
echo "* ready"
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue