This commit is contained in:
Murphy 2023-12-30 15:23:30 -05:00
parent ab75f7f7e3
commit 9ea034f420
No known key found for this signature in database
GPG key ID: 988032A5638EE799
12 changed files with 292 additions and 284 deletions

View file

@ -1,12 +1,17 @@
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 apk add --no-cache openrc udev-init-scripts-openrc wireguard-tools bind-tools bird
RUN mkdir -p /var/lib/inet2
COPY ./bin /usr/local/bin
COPY ./lib /var/lib/inet2
COPY ./deployments/openrc/inet2.initd /etc/init.d/inet2
COPY ./deployments/docker/wait.initd /etc/init.d/wait
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"]
RUN rm -rf /run/openrc 2>/dev/null
RUN mkdir /run/openrc
RUN touch /run/openrc/softlevel
COPY ./deployments/docker/entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]

11
Makefile Normal file
View file

@ -0,0 +1,11 @@
.PHONY: install
install:
mkdir -p /var/lib/inet2
cp ./bin/* /usr/local/bin
cp ./lib/* /var/lib/inet2
alpine:
apk add --no-cache wireguard-tools bind-tools bird
cp ./deployments/openrc/inet2.initd /etc/init.d/inet2
rc-update add inet2

156
README.md
View file

@ -1,102 +1,116 @@
# freyanet
this container allows perring multiple servers togeather with ospf creating an internetwork on any subnet
peer multiple ospf nodes over wireguard to make an internal network
## running
`docker run --privileged --network host -v $PWD/config:/config g.freya.cat/freya/freyanet`
or with docker-compose:
### docker
```yml
version: "3"
services:
inet2:
image: g.freya.cat/freya/freyanet
network_mode: host # needed otherwise internal network wont be accessable
privileged: true
volumes:
- ./config:/config
image: g.freya.cat/freya/freyanet
network_mode: host # needed otherwise internal network wont be accessable
privileged: true
volumes:
- ./inet2.conf:/etc/inet2.conf
```
### host
run the following commands with the provided makefile
```bash
$ make
$ make <os>
```
the current supported os's are: `alpine`
start the `inet2` service to start freyanet
## config
create a file at /config/inet2.conf
- if running in docker mount a file called `inet2.conf` at `/etc/inet2.conf`
- if running on host make a file called `/etc/inet2.conf`
```
# specify router id
# specify router id for ospf
RouterID 10.1.1.1
# optionally assign static addresses to the loopback interface
Loopback 1.2.3.4
# specify routed subnets
# ips that are not in these subnets will be ignored
# put the ip blocks for your entire internal network
Subnet 10.0.0.0/8
Subnet fd:cafe::/48
Subnet fd:cafe::/32
# specify node stubnets
# ip blocks that this node is gurenteed to route
Stubnet 10.1.0.0/8
Stubnet fd:cafe:dead::/48
# optional global private key gets used for all interfaces
PrivateKey = {host private key}
# create a peered wireguard interface
# specify addresses, routes, ports, pre/post commands, and peers
# keys can be generated with wg genkey and wg pubkey
interface interfacename
# indentation is a single tab per level
# indentation is a single tab per level
# otherwise file will fail to parse
# set the address(es) to assign to the interface
# route lines are usually the same as Address but with host bits zeroed
Address 10.2.255.1/30
Route 10.2.255.0/30 # must specify route
# you can also set ipv6
Address fd:cafe::ffff/64
Address fd:cafe::/64
# link local is also possible (and prefered for peering routers)
# link-local addresses should *not* have an associated Route line
Address fe80::1/64
Route 1.1.1.0/24
# more syntax options
Route 1.1.2.0/24 via 1.1.1.2
Route default via 1.1.1.3
# optional: set Gateway and Gateway6 to configure a default gateway
# through this interface
Gateway 1.1.1.2
Gateway6 fe80::1111:1111:1111:1111
# port to listen on in the host's network namespace, over udp
# you probably have to allow this through your firewall
ListenPort {host port}
# omit if using global private key
PrivateKey {host private key}
# all optional
PreUp command
PostUp command
PreDown command
PostDown command
# if running ospf on this interface
OSPF
# if running ospf on this interface and it's a stub network (no other routers)
OSPF stub
peer peername
PublicKey {peer public key}
# if the peer is a router, it has to have AllowedIPs set to everything and be the only
# peer on the interface
AllowedIPs 0.0.0.0/0, ::/0
# either:
Domain = {domain name of peer}
Port = {peer port}
# or:
Endpoint = {peer ip}:{peer port}
# make domain enpoint resolve with ipv (ipv6 is default)
IPv4
# optional
PersistentKeepalive = 25
# optionally assign static addresses to the loopback interface
# this has its uses for making things ibgp not dependent on a specific interface being up
Loopback 1.2.3.4
# set the address(es) to assign to the interface
# route lines are usually the same as Address but with host bits zeroed
Address 10.2.255.1/30
Route 10.2.255.0/30 # must specify route
# you can also set ipv6
Address fd:cafe::ffff/64
Address fd:cafe::/64
# link local is also possible (and prefered for peering routers)
# link-local addresses should *not* have an associated Route line
Address fe80::1/64
Route 1.1.1.0/24
# more syntax options
Route 1.1.2.0/24 via 1.1.1.2
Route default via 1.1.1.3
# port to listen on in the host's network namespace, over udp
# you probably have to allow this through your firewall
ListenPort {host port}
# omit if using global private key
PrivateKey {host private key}
# all optional
PreUp command
PostUp command
PreDown command
PostDown command
# if running ospf on this interface
OSPF
# if running ospf on this interface and it's a stub network (no other routers)
OSPF stub
peer peername
PublicKey {peer public key}
# if the peer is a router, it has to have AllowedIPs set to everything and be the only
# peer on the interface
AllowedIPs 0.0.0.0/0, ::/0
# either:
Domain = {domain name of peer}
Port = {peer port}
# or:
Endpoint = {peer ip}:{peer port}
# make domain enpoint resolve with ipv (ipv6 is default)
IPv4
# optional
PersistentKeepalive = 25
```
and other optional files:
- `/config/setup.sh` gets run on the first run of the container with the host's networking
- `/config/start.sh` gets run every time the container starts up with the host's networking
### Licenses
## licenses
| License | Author | Project |
|---------|--------|---------|

View file

@ -1,20 +1,6 @@
#!/sbin/openrc-run
name="inet2"
description="Sets up wireguard interfaces connected via the host's internet connection"
#!/usr/bin/env sh
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 "$@"
}
. /var/lib/inet2/inet2.sh
runscripts() {
if [ -n "$(getval "interface $2" "$1")" ]; then
@ -25,23 +11,24 @@ runscripts() {
fi
}
start() {
step "Starting inet2"
step "Removing old Wireguard interfaces"
for file in /sys/class/net/*; do # Clear all wireguard interfaces
type=$(cat "$file/type")
if [ "$type" = "65534" ]; then
ifname="$(basename $file)"
ip link del "$ifname"
ifname="$(basename $file)"
run ip link del "$ifname"
fi
done
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
rm -fr /run/inet2/wg 2> /dev/null
mkdir -p /run/inet2/wg
mkbirdconfig.sh
step "Setting loopback addresses"
getval Loopback | while read -r addr; do
run ip addr add "$addr" dev lo
done
@ -84,36 +71,35 @@ start() {
}
stop() {
if [ -f /run/inet2/inet2.conf ]; then
getval Loopback | while read -r addr; do
run ip addr del "$addr" dev lo
done
step "Stopping inet2"
step "Removing loopback"
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
getval interface | while read -r inter; do
runscripts PreDown "$inter"
rm -rf /run/inet2/inet2.conf
fi
step "Bringing $inter down"
run ip link del "$inter"
runscripts PostDown "$inter"
done
}
# 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
reload() {
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
}
restart() {
stop
start
}
$1

84
bin/mkbirdconfig.sh Executable file
View file

@ -0,0 +1,84 @@
#!/bin/sh
. /var/lib/inet2/inet2.sh
escapebird() {
sed -e 's/\\/\\\\/g;s/"/\\"/g'
}
step "Creating Bird configuration"
touch /var/log/bird.log
chown bird:bird /var/log/bird.log
interfacelist=$(
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)\" {"
echo " type ptp;"
if [ -n "$val" ]; then
echo " $val;";
fi
echo " };"
fi
done
)
filter4=$(getval "Subnet" | grep -v ':' | while read -r line; do printf "%s+," "$line"; done | sed 's/,$//')
filter6=$(getval "Subnet" | grep ':' | while read -r line; do printf "%s+," "$line"; done | sed 's/,$//')
(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 net ~ [$filter4] then accept; else reject; }; };
}
protocol kernel {
ipv6 { export filter { if net ~ [$filter6] then accept; else reject; }; };
}
protocol device {
}
protocol direct {
ipv4;
ipv6;
}
protocol static {
ipv4;
}
EOF
cat <<EOF
protocol ospf v3 ospf4 {
ipv4 {
import all;
export filter { if source ~ [RTS_DEVICE, RTS_INHERIT] && net ~ [$filter4] then accept; else reject; };
};
area 0 {
$(getval "Stubnet" | grep -v ':' | while read -r net; do echo " stubnet $net {};"; done)
$interfacelist
};
}
protocol ospf v3 ospf6 {
ipv6 {
import all;
export filter { if source ~ [RTS_DEVICE, RTS_INHERIT] && net ~ [$filter6] then accept; else reject; };
};
area 0 {
$(getval "Stubnet" | grep ':' | while read -r net; do echo " stubnet $net {};"; done)
$interfacelist
};
}
EOF
) > /etc/bird.conf
chown root:bird /etc/bird.conf
chmod 640 /etc/bird.conf

View file

@ -1,14 +1,11 @@
#!/bin/sh
#!/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
configfile=/etc/inet2.conf
getval() {
/usr/local/bin/config.awk "$configfile" "$@"
/var/lib/inet2/config.awk "$configfile" "$@"
}
k() {

View file

@ -0,0 +1,12 @@
#!/bin/sh
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

26
deployments/openrc/inet2.initd Executable file
View file

@ -0,0 +1,26 @@
#!/sbin/openrc-run
name="inet2"
description="Sets up wireguard interfaces connected via the host's internet connection"
extra_started_commands="reloadwg"
start() {
/usr/local/bin/inet2.sh start
rc-service bird start 2> /dev/null
}
stop() {
/usr/local/bin/inet2.sh stop
rc-service bird stop 2> /dev/null
}
restart() {
stop
start
}
reload() {
/usr/local/bin/inet2.sh reload
rc-service bird restart 2> /dev/null
}

22
lib/inet2.sh Executable file
View file

@ -0,0 +1,22 @@
#!/usr/bin/env sh
run() {
printf '$ \x1b[32;1m%s\x1b[0m\n' "$*"
"$@"
}
step() {
printf '\x1b[34;1m>> %s\x1b[0m\n' "$*"
}
getval() {
/var/lib/inet2/config.awk /etc/inet2.conf "$@"
}
haskey() {
getval interface | while read -r inter; do
if getval "interface $inter" "$1"; then
echo "true"
return
fi
done
}

149
setup.sh
View file

@ -1,149 +0,0 @@
#!/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 all; };
}
protocol kernel {
ipv6 { export all; };
}
protocol device {
}
protocol direct {
ipv4;
ipv6;
}
protocol static {
ipv4;
}
EOF
if [ -n "$ospf" ]; then
interfacelist=$(
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)\" {"
echo " type ptp;"
if [ -n "$val" ]; then
echo " $val;";
fi
echo " };"
fi
done
)
cat <<EOF
protocol ospf v3 ospf4 {
ipv4 {
import all;
export filter { if source ~ [RTS_DEVICE, RTS_INHERIT] && net ~ [$(getval "Subnet" | grep -v ':' | while read -r line; do printf "%s+," "$line"; done | sed 's/,$//')] then accept; else reject; };
};
area 0 {
$(getval "Stubnet" | grep -v ':' | while read -r net; do echo " stubnet $net {};"; done)
$interfacelist
};
}
protocol ospf v3 ospf6 {
ipv6 {
import all;
export filter { if source ~ [RTS_DEVICE, RTS_INHERIT] && net ~ [$(getval "Subnet" | grep ':' | while read -r line; do printf "%s+," "$line"; done | sed 's/,$//')] then accept; else reject; };
};
area 0 {
$(getval "Stubnet" | grep ':' | while read -r net; do echo " stubnet $net {};"; done)
$interfacelist
};
}
EOF
fi
) > /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