diff options
| -rwxr-xr-x | etc/local.d/00-dhcpcd.start | 44 | ||||
| -rwxr-xr-x | etc/local.d/00-net.start | 21 | ||||
| -rwxr-xr-x | etc/local.d/01-iptables.start | 59 | ||||
| -rwxr-xr-x | etc/local.d/02-dnsmasq.start | 23 | ||||
| -rwxr-xr-x | etc/local.d/03-miniupnpd.start | 33 | ||||
| -rwxr-xr-x | etc/local.d/radvd.hook | 42 | ||||
| -rwxr-xr-x | etc/local.d/vars.sh | 17 | ||||
| -rwxr-xr-x | etc/local.d/vars_end.sh | 3 | ||||
| -rw-r--r-- | readme.md | 41 |
9 files changed, 283 insertions, 0 deletions
diff --git a/etc/local.d/00-dhcpcd.start b/etc/local.d/00-dhcpcd.start new file mode 100755 index 0000000..65d8957 --- /dev/null +++ b/etc/local.d/00-dhcpcd.start @@ -0,0 +1,44 @@ +#!/bin/sh +. /etc/local.d/vars.sh +# Not actually starting dhcpcd here, just writing out the configuration +# file based on what we have in vars +# +# This file also installs the `radvd.hook` to enable ipv6 router advertisements +# on the lan interface. + +# Write out our dhcpcd conf, take note that I've specifically disabled ipv4 +# here. I could enable it, however to keep a static ipv4 address the same as +# with a previous router it makes sense to have a DHCPv4 server not using a +# duid. ( So, udhcpc is still used ) +cat > /etc/dhcpcd.conf <<EOF +duid +nodhcp +noipv4 +noipv4ll +dhcp6 +persistent +vendorclassid +option domain_name_servers, domain_name, domain_search +option classless_static_routes +option interface_mtu +option host_name +option rapid_commit +require dhcp_server_identifier +slaac private +noipv6rs +denyinterfaces $lan +interface $wan + ipv6rs + ia_na 1 + ia_pd 2 $lan/0 +EOF + +echo "Generated dhcpcd.conf:" + +cat /etc/dhcpcd.conf + +# Copy the dhcpcd hook for radvd into place +cp /etc/local.d/radvd.hook \ + /usr/lib/dhcpcd/dhcpcd-hooks/60-radvd.conf + +. /etc/local.d/vars_end.sh diff --git a/etc/local.d/00-net.start b/etc/local.d/00-net.start new file mode 100755 index 0000000..9c28f09 --- /dev/null +++ b/etc/local.d/00-net.start @@ -0,0 +1,21 @@ +#!/bin/sh +. /etc/local.d/vars.sh + +ip link set dev $wan address $wan_hwaddr +ip link set up $wan +udhcpc -b -i $wan + +# dhcpv6 +dhcpcd + +ip link set up $lan +ip -4 addr add $lan_ip/$lan_mask_bits dev $lan + +# We are indeed, a router. +sysctl -w net.ipv4.ip_forward=1 +# Even though we're a router, accept router advertisements anyway +sysctl -w net.ipv6.conf.all.accept_ra=2 +# IP Forwarding, but for ipv6 as well +sysctl -w net.ipv6.conf.all.forwarding=1 + +. /etc/local.d/vars_end.sh diff --git a/etc/local.d/01-iptables.start b/etc/local.d/01-iptables.start new file mode 100755 index 0000000..0778a15 --- /dev/null +++ b/etc/local.d/01-iptables.start @@ -0,0 +1,59 @@ +#!/bin/sh +. /etc/local.d/vars.sh +wan_ip="$(ip -4 addr show dev eth0 | awk '/inet/{print $2}' | sed -e's@/.*$@@g')" +ipt=iptables +ipt6=ip6tables + + +# Set policies +for chain in INPUT OUTPUT FORWARD ; do + $ipt -F $chain + $ipt -P $chain ACCEPT + $ipt6 -F $chain + $ipt6 -P $chain ACCEPT +done + +$ipt -A INPUT -i lo -j ACCEPT +$ipt -A INPUT -m conntrack --ctstate related,established -j ACCEPT +$ipt -A INPUT -p tcp --dport 22 -d $lan_ip -j ACCEPT # SSH internally +$ipt -A INPUT -p tcp --dport 9100 -j ACCEPT # prometheus node exporter +$ipt -A INPUT -p tcp --dport 443 -j ACCEPT # HTTPs +$ipt -A INPUT -i $lan -j ACCEPT +$ipt -A INPUT -i $lan -p icmp -j ACCEPT +$ipt -A INPUT -j DROP + +$ipt6 -A INPUT -i lo -j ACCEPT +$ipt6 -A INPUT -m state --state related,established -j ACCEPT +$ipt6 -A INPUT -p udp --dport 546 -d fe80::/10 -j ACCEPT # Router advertisements +$ipt6 -A INPUT -p icmpv6 -j ACCEPT +$ipt6 -A INPUT -j REJECT + +$ipt6 -A FORWARD -m state --state related,established -j ACCEPT +$ipt6 -A FORWARD -i $lan -j ACCEPT +$ipt6 -A FORWARD -p icmpv6 -j ACCEPT +$ipt6 -A FORWARD -j REJECT + + +# Policies for NAT +for chain in INPUT OUTPUT PREROUTING POSTROUTING ; do + $ipt -t nat -F $chain + $ipt -t nat -P $chain ACCEPT +done + +# Multiple port forwards for 10.0.0.241 with NAT relfection as an example: +internal_server=10.0.0.241 +for port in 443 9100 9090 ; do + $ipt -t nat -A PREROUTING -p tcp --dport $port -d $wan_ip \ + -j DNAT --to $internal_server + # and nat reflection for said server: + $ipt -t nat -I PREROUTING -p tcp --dport $port -d $lan_ip -i eth0 \ + -j DNAT --to $internal_server + $ipt -t nat -I POSTROUTING -p tcp --dport $port -d $internal_server \ + -j SNAT --to $lan_ip +done + +# Where the "magic" happens for IPv4, translate local IPs to that of +# the $wan interface. +$ipt -t nat -A POSTROUTING -o $wan -j MASQUERADE + +. /etc/local.d/vars_end.sh diff --git a/etc/local.d/02-dnsmasq.start b/etc/local.d/02-dnsmasq.start new file mode 100755 index 0000000..25b736c --- /dev/null +++ b/etc/local.d/02-dnsmasq.start @@ -0,0 +1,23 @@ +#!/bin/sh +# Generate dnsmasq configuration +. /etc/local.d/vars.sh +conf="/etc/dnsmasq.conf" + +cat > "$conf" <<EOF +no-resolv +$(for server in $dns_servers ; do printf 'server=%s\n' $server ; done) +domain-needed +except-interface=$wan +expand-hosts +domain=$domain +dhcp-range=$dhcp_range +# This is the default +#dhcp-leasefile=/var/lib/misc/dnsmasq.leases +dhcp-authoritative +EOF + +echo "Generated dnasmasq config:" + +cat $conf + +. /etc/local.d/vars_end.sh diff --git a/etc/local.d/03-miniupnpd.start b/etc/local.d/03-miniupnpd.start new file mode 100755 index 0000000..a1a0656 --- /dev/null +++ b/etc/local.d/03-miniupnpd.start @@ -0,0 +1,33 @@ +#!/bin/sh +. /etc/local.d/vars.sh +conf="/etc/miniupnpd/miniupnpd.conf" +lease_file=/var/lib/misc/upnp.leases + +cat > "$conf" <<EOF +ext_ifname=$wan +listening_ip=$lan +# ext_ip= +# ext_stun_host=stun.stunprotocol.org +# ext_perform_stun=yes +model_number=$(uname -r | grep -oE '[0-9.]+' | sed 1q) +serial=12345678 +enable_natpmp=yes +enable_upnp=yes +lease_file=$lease_file +# Secure Mode, UPnP clients can only add mappings to their own IP +secure_mode=yes +presentation_url=http://$lan_ip +clean_ruleset_interval=600 +min_lifetime=120 +max_lifetime=86400 +# UUID, generate your own UUID with "make genuuid" +uuid=$(uuidgen) +# allow 1024-65535 $lan_net/$lan_mask_bits 1024-65535 +# deny 0-65535 0.0.0.0/0 0-65535 +EOF + +echo "Generating miniupnpd conf:" + +cat "$conf" + +. /etc/local.d/vars_end.sh diff --git a/etc/local.d/radvd.hook b/etc/local.d/radvd.hook new file mode 100755 index 0000000..8137d0b --- /dev/null +++ b/etc/local.d/radvd.hook @@ -0,0 +1,42 @@ +#!/bin/sh +# Brutally simply hook for dhcpcd assuming you only have a single interface with +# delegated prefixes, which is the case for most home routers. + +# This writes out a radvd conf for the interface and prefix in question and +# blindly restarts the daemon. + +write_radvd() { + +if [ -z "$new_delegated_dhcp6_prefix" ] ; then + echo "Cannot continue without delegated prefix" + exit 1; +fi + +conf="interface $interface { + AdvSendAdvert on;" + +for prefix in $new_delegated_dhcp6_prefix ; do +conf="$conf + prefix $prefix + { + AdvOnLink on; + AdvAutonomous on; + AdvRouterAddr on; + }; +" +done + +conf="$conf +};" + +echo "$conf" > /etc/radvd.conf + +/etc/init.d/radvd restart +} + +case "$reason" in +DELEGATED6) +write_radvd +;; +esac + diff --git a/etc/local.d/vars.sh b/etc/local.d/vars.sh new file mode 100755 index 0000000..dcc326c --- /dev/null +++ b/etc/local.d/vars.sh @@ -0,0 +1,17 @@ +# You can replace tty1 with ttyS0 for serial output +exec >/dev/tty1 2>&1 +printf '\033[1;32m' # Green output for our scripts, comment out to disable. +echo "Starting script: $0" +set -x + +wan=eth0 # WAN / ISP uplink interface, assumed ip is provided by DHCP +wan_hwaddr=EA:5D:EA:DB:EE:FF +lan=eth1 # LAN interface +# `sipcalc` is a useful program here +lan_ip=192.168.0.1 +lan_net=192.168.0.0 +lan_mask_bits=24 +domain=router.local +dhcp_range=192.168.0.30,192.168.0.230,24h +# Specifically overrides upstream on `dnsmasq` for the DHCP clients +dns_servers="1.1.1.1 8.8.4.4" diff --git a/etc/local.d/vars_end.sh b/etc/local.d/vars_end.sh new file mode 100755 index 0000000..d2c4c2c --- /dev/null +++ b/etc/local.d/vars_end.sh @@ -0,0 +1,3 @@ +set +x +echo "Ending script: $0" +printf '\033[0m\n' # Stop color output diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..97a8da6 --- /dev/null +++ b/readme.md @@ -0,0 +1,41 @@ +# Alpine Linux Home Router + +A small set of shell scripts you can drop into `/etc/local.d/` +that will turn an Alpine Linux machine into a home router. The functionality +includes IPv6 via DHCPv6 and port dynamic forwarding via miniupnpd ( optional ) + +## Configuration + +All major configuration options are in `/etc/local.d/vars.sh` + +Simply adjust `wan_hwaddr` if yo so desire, set the `wan` and `lan` interfaces +and the scripts will take care of the rest. + +The `radvd` daemon will automatically be started by the `dhcpcd` hook. + +`dnsmasq` for DHCPv4 on the LAN needs to be enabled by hand. + +`miniupnpd` is not enabled by default, though it is configured. + +## Installation + +On a complete Alpine Linux install, copy the files to `/etc/local.d`, +then run: + +``` +# apk add iptables ip6tables dnsmasq miniupnpd dhcpcd radvd curl +# rc-update add local boot +# rc-update add dnsmasq default +``` + +For a basic configuration. Reboot for it to take effect. It's wise to disable +all other network configuration on the box before you do so. + +For a more in-depth tutorial [see my blog post](https://riedstra.dev/2022/02/alpine-linux-home-router). + +## UPNP Considerations + +UPNP can be dangerous, if you don't trust the devices on your network turn it +off, or block the port to all but the devices you trust. + + |
