things
This commit is contained in:
commit
8b7fe69ca3
6 changed files with 357 additions and 0 deletions
12
Dockerfile
Normal file
12
Dockerfile
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
FROM alpine
|
||||||
|
RUN apk add --no-cache wireguard-tools bind-tools bird openrc udev-init-scripts-openrc
|
||||||
|
COPY ./wait.initd /etc/init.d/wait
|
||||||
|
COPY ./inet2.initd /etc/init.d/inet2
|
||||||
|
RUN sed -i 's/#rc_sys=""/rc_sys="docker"/' /etc/rc.conf && \
|
||||||
|
rc-update add wait && \
|
||||||
|
rc-update add inet2
|
||||||
|
COPY ./setup.sh /setup.sh
|
||||||
|
COPY ./bin /usr/local/bin
|
||||||
|
|
||||||
|
ENTRYPOINT ["/setup.sh"]
|
||||||
|
|
35
bin/config.awk
Executable file
35
bin/config.awk
Executable file
|
@ -0,0 +1,35 @@
|
||||||
|
#!/run/current-system/profile/bin/awk -f
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
FS = "[ ]"; # use a single space as field separator and don't trim input
|
||||||
|
ind = 0; # indentation level
|
||||||
|
last = ARGC - 3; # last argument index
|
||||||
|
exitcode = 1; # whether anything has been matched
|
||||||
|
if(last < 0) { # there should be at least one argument after the filename
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
ARGC = 2; # don't read ARGV[2] and onward as files
|
||||||
|
}
|
||||||
|
|
||||||
|
END {
|
||||||
|
exit exitcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
$0 != "" { # exit when the indentation block is exited
|
||||||
|
for(i = 0; i < ind; i++) {
|
||||||
|
if(! sub(/^\t/, "")) {
|
||||||
|
exit exitcode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# if on the last argument, interpret it as a key and print the value
|
||||||
|
ind == last && $1 == ARGV[ind + 2] {
|
||||||
|
exitcode = 0;
|
||||||
|
print substr($0, length($1) + 2);
|
||||||
|
}
|
||||||
|
# if not on the last argument, find the string exactly and increment indentation
|
||||||
|
ind != last && $0 == ARGV[ind + 2] {
|
||||||
|
ind++;
|
||||||
|
}
|
||||||
|
|
51
bin/mkwgconfig.sh
Executable file
51
bin/mkwgconfig.sh
Executable file
|
@ -0,0 +1,51 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
# args: /path/to/interface-config /path/to/output.conf
|
||||||
|
|
||||||
|
inter="$1"
|
||||||
|
configfile="$3"
|
||||||
|
if [ -z "$configfile" ]; then
|
||||||
|
configfile=/run/inet2/inet2.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
getval() {
|
||||||
|
/usr/local/bin/config.awk "$configfile" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
k() {
|
||||||
|
while read -r line; do
|
||||||
|
echo "$1 = $line"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
echo "[Interface]"
|
||||||
|
getval "interface $inter" ListenPort | k ListenPort
|
||||||
|
getval "interface $inter" PrivateKey | k PrivateKey
|
||||||
|
getval PrivateKey | k PrivateKey
|
||||||
|
echo
|
||||||
|
|
||||||
|
getval "interface $inter" peer | while read -r peer; do
|
||||||
|
echo "[Peer]"
|
||||||
|
getval "interface $inter" "peer $peer" PublicKey | k PublicKey
|
||||||
|
getval "interface $inter" "peer $peer" AllowedIPs | k AllowedIPs
|
||||||
|
|
||||||
|
domain="$(getval "interface $inter" "peer $peer" Domain)"
|
||||||
|
if [ -n "$domain" ]; then
|
||||||
|
# it doesn't like domain names in the Endpoint field, so resolve dns here
|
||||||
|
v4="$(dig +short "$domain")"
|
||||||
|
[ ! "$?" = "0" ] && v4=""
|
||||||
|
v6="$(dig +short -t aaaa "$domain")"
|
||||||
|
[ ! "$?" = "0" ] && v6=""
|
||||||
|
if getval "interface $inter" "peer $peer" IPv4; then
|
||||||
|
v6=""
|
||||||
|
fi
|
||||||
|
addr="[$v6]"
|
||||||
|
[ "$addr" = "[]" ] && addr="$v4"
|
||||||
|
echo "Endpoint = $addr:$(getval "interface $inter" "peer $peer" Port)"
|
||||||
|
else
|
||||||
|
getval "interface $inter" "peer $peer" Endpoint | k Endpoint
|
||||||
|
fi
|
||||||
|
getval "interface $inter" "peer $peer" PersistentKeepalive | k PersistentKeepalive
|
||||||
|
echo
|
||||||
|
done
|
||||||
|
) > "$2"
|
108
inet2.initd
Executable file
108
inet2.initd
Executable file
|
@ -0,0 +1,108 @@
|
||||||
|
#!/sbin/openrc-run
|
||||||
|
name="inet2"
|
||||||
|
description="Sets up wireguard interfaces connected via the host's internet connection"
|
||||||
|
|
||||||
|
extra_started_commands="reloadwg"
|
||||||
|
|
||||||
|
run() {
|
||||||
|
printf '$ \x1b[32;1m%s\x1b[0m\n' "$*"
|
||||||
|
"$@"
|
||||||
|
}
|
||||||
|
step() {
|
||||||
|
printf '\x1b[34;1m>> %s\x1b[0m\n' "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
getval() {
|
||||||
|
/usr/local/bin/config.awk /run/inet2/inet2.conf "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
runscripts() {
|
||||||
|
if [ -n "$(getval "interface $2" "$1")" ]; then
|
||||||
|
step "Running $1 for $2"
|
||||||
|
getval "interface $2" "$1" | while read -r line; do
|
||||||
|
(eval "$line")
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
rm -rf /run/inet2/config 2>/dev/null
|
||||||
|
rm -rf /run/inet2/wg 2>/dev/null
|
||||||
|
cp /config/inet2.conf /run/inet2/inet2.conf
|
||||||
|
mkdir /run/inet2/wg
|
||||||
|
|
||||||
|
getval Loopback | while read -r addr; do
|
||||||
|
run ip addr add "$addr" dev lo
|
||||||
|
done
|
||||||
|
|
||||||
|
getval interface | while read -r inter; do
|
||||||
|
step "Generating config for $inter"
|
||||||
|
run mkwgconfig.sh "$inter" /run/inet2/wg/"$inter"
|
||||||
|
|
||||||
|
# create the wireguard interface *in the default namespace*
|
||||||
|
step "Adding Wireguard interface $inter"
|
||||||
|
run ip link add name "$inter" type wireguard
|
||||||
|
|
||||||
|
# set up the new network from the config
|
||||||
|
step "Setting Wireguard config for $inter"
|
||||||
|
run wg setconf "$inter" /run/inet2/wg/"$inter"
|
||||||
|
|
||||||
|
# the config doesn't actually add any addresses, do that here
|
||||||
|
step "Adding host addresses for $inter"
|
||||||
|
getval "interface $inter" Address | while read -r addr; do
|
||||||
|
run ip addr add "$addr" dev "$inter"
|
||||||
|
done
|
||||||
|
|
||||||
|
runscripts PreUp "$inter"
|
||||||
|
|
||||||
|
step "Bringing interface up"
|
||||||
|
run ip link set dev "$inter" up
|
||||||
|
|
||||||
|
getval "interface $inter" Route | while read -r line; do
|
||||||
|
read -r route via addr2 < <(printf "%s" "$line")
|
||||||
|
if [ "$via" = "via" ]; then
|
||||||
|
run ip route add "$route" via "$addr2" dev "$inter"
|
||||||
|
else
|
||||||
|
run ip route add "$route" dev "$inter"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
runscripts PostUp "$inter"
|
||||||
|
done
|
||||||
|
step "Done!"
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
if [ -f /run/inet2/inet2.conf ]; then
|
||||||
|
getval Loopback | while read -r addr; do
|
||||||
|
run ip addr del "$addr" dev lo
|
||||||
|
done
|
||||||
|
|
||||||
|
getval interface | while read -r inter; do
|
||||||
|
runscripts PreDown "$inter"
|
||||||
|
|
||||||
|
step "Bringing $inter down"
|
||||||
|
run ip link del "$inter"
|
||||||
|
|
||||||
|
runscripts PostDown "$inter"
|
||||||
|
done
|
||||||
|
|
||||||
|
rm -rf /run/inet2/inet2.conf
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# just reloads the wireguard configs for existing interfaces
|
||||||
|
# for if a peer's domain name resolves to a different ip address now
|
||||||
|
# and it needs to be re-resolved without taking down the connection
|
||||||
|
reloadwg() {
|
||||||
|
if [ -f /run/inet2/inet2.conf ]; then
|
||||||
|
getval interface | while read -r inter; do
|
||||||
|
step "Generating config for $inter"
|
||||||
|
run mkwgconfig.sh "$inter" /run/inet2/wg/"$inter" /config/inet2.conf
|
||||||
|
|
||||||
|
step "Setting Wireguard config for $inter"
|
||||||
|
run wg setconf "$inter" /run/inet2/wg/"$inter"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
147
setup.sh
Executable file
147
setup.sh
Executable file
|
@ -0,0 +1,147 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
run() {
|
||||||
|
printf '$ \x1b[32;1m%s\x1b[0m\n' "$*"
|
||||||
|
"$@"
|
||||||
|
}
|
||||||
|
step() {
|
||||||
|
printf '\x1b[34;1m>> %s\x1b[0m\n' "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
getval() {
|
||||||
|
/usr/local/bin/config.awk /config/inet2.conf "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
haskey() {
|
||||||
|
getval interface | while read -r inter; do
|
||||||
|
if getval "interface $inter" "$1"; then
|
||||||
|
echo "true"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# ensure the /run/inet2 directory is empty (docker doesn't mount tmpfs to /run)
|
||||||
|
# /run/inet2 is used for storage during runtime - restarting the container should clear it
|
||||||
|
rm -rf /run/inet2 2>/dev/null
|
||||||
|
mkdir /run/inet2
|
||||||
|
|
||||||
|
# ensure the /var/lib/inet2 directory exists
|
||||||
|
# /var/lib/inet2 is used for storage for the entire lifetime of the container - restarting the container shouldn't clear it
|
||||||
|
if [ ! -d /var/lib/inet2 ]; then
|
||||||
|
mkdir -p /var/lib/inet2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# these are disabled in the docker netns
|
||||||
|
step "Enabling IPv6"
|
||||||
|
run sysctl net.ipv6.conf.all.disable_ipv6=0 net.ipv6.conf.default.disable_ipv6=0 net.ipv6.conf.all.forwarding=1
|
||||||
|
|
||||||
|
ospf="$(haskey OSPF)"
|
||||||
|
|
||||||
|
escapebird() {
|
||||||
|
sed -e 's/\\/\\\\/g;s/"/\\"/g'
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -n "$ospf" ]; then
|
||||||
|
step "Creating Bird configuration"
|
||||||
|
|
||||||
|
touch /var/log/bird.log
|
||||||
|
chown bird:bird /var/log/bird.log
|
||||||
|
|
||||||
|
selfas=$(getval AS)
|
||||||
|
(
|
||||||
|
cat <<EOF
|
||||||
|
log "/var/log/bird.log" all;
|
||||||
|
|
||||||
|
$(getval RouterID | while read -r line; do echo "router id $line;"; done)
|
||||||
|
|
||||||
|
protocol kernel {
|
||||||
|
ipv4 {
|
||||||
|
export filter { if source ~ [RTS_BGP, RTS_OSPF, RTS_OSPF_IA, RTS_OSPF_EXT1, RTS_OSPF_EXT2] then accept; else reject; };
|
||||||
|
import all;
|
||||||
|
};
|
||||||
|
learn;
|
||||||
|
scan time 10;
|
||||||
|
}
|
||||||
|
protocol kernel {
|
||||||
|
ipv6 {
|
||||||
|
export filter { if source ~ [RTS_BGP, RTS_OSPF, RTS_OSPF_IA, RTS_OSPF_EXT1, RTS_OSPF_EXT2] then accept; else reject; };
|
||||||
|
import all;
|
||||||
|
};
|
||||||
|
learn;
|
||||||
|
scan time 10;
|
||||||
|
}
|
||||||
|
protocol device {
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol direct {
|
||||||
|
ipv4;
|
||||||
|
ipv6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EOF
|
||||||
|
if [ -n "$ospf" ]; then
|
||||||
|
interfacelist=$(
|
||||||
|
echo " area 0 {"
|
||||||
|
echo " interface \"lo\" { stub; };"
|
||||||
|
getval interface | while read -r inter; do
|
||||||
|
val="$(getval "interface $inter" OSPF)"
|
||||||
|
if [ "$?" = "0" ]; then
|
||||||
|
echo " interface \"$(printf "%s" "$inter" | escapebird)\" {"
|
||||||
|
if [ -n "$val" ]; then
|
||||||
|
echo " $val;";
|
||||||
|
fi
|
||||||
|
echo " };"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo " };"
|
||||||
|
)
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
protocol ospf v3 ospf4 {
|
||||||
|
ipv4 {
|
||||||
|
import all;
|
||||||
|
export filter { if source ~ [RTS_DEVICE, RTS_INHERIT] then accept; else reject; };
|
||||||
|
};
|
||||||
|
$interfacelist
|
||||||
|
}
|
||||||
|
protocol ospf v3 ospf6 {
|
||||||
|
ipv6 {
|
||||||
|
import all;
|
||||||
|
export filter { if source ~ [RTS_DEVICE, RTS_INHERIT] then accept; else reject; };
|
||||||
|
};
|
||||||
|
$interfacelist
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
) > /etc/bird.conf
|
||||||
|
chown root:bird /etc/bird.conf
|
||||||
|
chmod 640 /etc/bird.conf
|
||||||
|
|
||||||
|
step "Enabling BIRD"
|
||||||
|
run rc-update add bird
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f /var/lib/inet2/setupDone ]; then
|
||||||
|
if [ -f /config/setup.sh ]; then
|
||||||
|
step "Running /config/setup.sh"
|
||||||
|
/config/setup.sh
|
||||||
|
fi
|
||||||
|
touch /var/lib/inet2/setupDone
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f /config/start.sh ]; then
|
||||||
|
step "Running /config/start.sh"
|
||||||
|
/config/start.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$#" = "0" ]; then
|
||||||
|
step "Starting OpenRC"
|
||||||
|
rm -rf /run/openrc 2>/dev/null
|
||||||
|
mkdir /run/openrc
|
||||||
|
touch /run/openrc/softlevel
|
||||||
|
exec /sbin/openrc
|
||||||
|
else
|
||||||
|
"$@"
|
||||||
|
fi
|
||||||
|
|
4
wait.initd
Executable file
4
wait.initd
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/sbin/openrc-run
|
||||||
|
# this container may need openrc to keep running without any services
|
||||||
|
# ordinarily that would cause it to stop, so this is a dummy service
|
||||||
|
start(){ sleep infinity & }
|
Loading…
Reference in a new issue