aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitchell Riedstra <mitch@riedstra.dev>2022-02-23 20:19:37 -0500
committerMitchell Riedstra <mitch@riedstra.dev>2022-02-23 20:43:27 -0500
commit12192865c3ca0e1c2139afabab508e0087b14982 (patch)
tree26ea5454dc976e87186e369685a1ac987bab2a61
downloadalpine-home-router-master.tar.gz
alpine-home-router-master.tar.xz
-rwxr-xr-xetc/local.d/00-dhcpcd.start44
-rwxr-xr-xetc/local.d/00-net.start21
-rwxr-xr-xetc/local.d/01-iptables.start59
-rwxr-xr-xetc/local.d/02-dnsmasq.start23
-rwxr-xr-xetc/local.d/03-miniupnpd.start33
-rwxr-xr-xetc/local.d/radvd.hook42
-rwxr-xr-xetc/local.d/vars.sh17
-rwxr-xr-xetc/local.d/vars_end.sh3
-rw-r--r--readme.md41
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.
+
+