Initial commit

Basic working code that is capable of establishing the Wireguard tunnel given that there is properly configured `.psk` file for at least one known wifi network (see README.md for more details)
This commit is contained in:
Lukas Stancik
2025-02-27 13:59:58 +00:00
commit 8176e71b81
27 changed files with 1355 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
# Tab indentation (no size specified)
[Makefile]
indent_style = tab
[*.mk]
indent_style = tab
[*.start]
indent_style = tab
+26
View File
@@ -0,0 +1,26 @@
BUILDER_UID=<%= $(id -u) %>
BUILDER_GID=<%= $(id -g) %>
BUILDER_USER=<%= $(whoami) %>
BUILDER_DOCKER_IMAGE=repository-builder
BUILDER_KEY_BASENAME=packager
CACHE_DIR=<%= $(pwd) %>/cache
ALPINE_MIRROR=https://dl-cdn.alpinelinux.org/alpine
ALPINE_ARCH=aarch64
ALPINE_VER_MAJOR=3
ALPINE_VER_MINOR=20
ALPINE_VER_PATCH=3
REQUIREMENTS_FILE=required-apks.txt
eth0=eth0
wlan0=wlan0
wlan1=wlan1
wg0=wg0
wg_port=51820
wg_server=31.31.79.229
hostname=entropi
ssid=entropi_nomap
wlan0_base=192.168.66
wg0_base=10.0.22
ROUTER_TIMEZONE=Europe/Prague
ROUTER_DNS_PRIMARY=1.1.1.1
ROUTER_NTP_PRIMARY=195.113.144.201
ROUTER_NTP_SECONDARY=195.113.144.238
+105
View File
@@ -0,0 +1,105 @@
.DEFAULT_GOAL:=build
TEMP_DIR=$(shell ./preflight)
DIST_DIR=${TEMP_DIR}/dist
DOT_ENV_FILE=${TEMP_DIR}/.env
DOT_ENV_PAIRS=$(shell cat ${DOT_ENV_FILE})
BUILD_ARGS=$(shell for ARG in ${DOT_ENV_PAIRS}; do echo "--build-arg $$ARG"; done;)
-include ${DOT_ENV_FILE}
vault/encrypt:
@echo "### Encrypting secrets..."
@./vault encrypt
@echo "### Encrypting done"
vault/decrypt:
@echo "### Decrypting secrets..."
@./vault decrypt
@echo "### Decrypting done"
init:
@echo "### Init..."
@./require ${DOT_ENV_FILE} alpine_source
@./require ${DOT_ENV_FILE} tailspin_bin
@./require ${DOT_ENV_FILE} age_bin
@echo "### Init done"
-@make vault/decrypt
build: repository
@echo "### Assembling..."
@rsync -chaz ${CACHE_DIR}/${RELEASE_BASENAME}/ ${DIST_DIR}
@mkdir -p ${TEMP_DIR}/overlay_headless/etc/local.d
@mkdir -p ${TEMP_DIR}/overlay_headless/etc/runlevels/default
@touch ${TEMP_DIR}/overlay_headless/etc/.default_boot_services
-@ln -s /etc/init.d/local ${TEMP_DIR}/overlay_headless/etc/runlevels/default/local
@./src/esh -o ${TEMP_DIR}/overlay_headless/etc/local.d/headless.start src/headless.start ${DOT_ENV_PAIRS}
@chmod +x ${TEMP_DIR}/overlay_headless/etc/local.d/headless.start
@tar czf ${DIST_DIR}/headless.apkovl.tar.gz -C ${TEMP_DIR}/overlay_headless/ .
@rsync -chaz ${CACHE_DIR}/aport/${RELEASE_VERSION}/main/ ${DIST_DIR}/extras
@cp ${CACHE_DIR}/tailspin/tspin ${DIST_DIR}
@./src/esh -o ${DIST_DIR}/hotspot.conf src/hotspot.conf ${DOT_ENV_PAIRS}
@./src/esh -o ${DIST_DIR}/wg0.conf src/wg0.conf ${DOT_ENV_PAIRS}
@cp secrets/*.psk ${DIST_DIR}
@cp src/authorized_keys ${DIST_DIR}
@cp src/config.toml ${DIST_DIR}
@cp src/logpattern.conf ${DIST_DIR}
@cp src/main.conf ${DIST_DIR}
@cp src/rsyslog.conf ${DIST_DIR}
@cp src/usercfg.txt ${DIST_DIR}
@cp src/watchdog.sh ${DIST_DIR}
@cp src/repository-builder/packager.rsa.pub ${DIST_DIR}
@cp src/repository-builder/${REQUIREMENTS_FILE} ${DIST_DIR}
@echo "### Assembling done"
@make vault/encrypt
card: clean build
@echo "### Copying to sdcard..."
@rsync -chavz --delete ${DIST_DIR}/ /media/$(shell whoami)/entropi
@echo "### Copying to sdcard done"
-@make clean
clean:
@echo "### Cleaning..."
-@rm -rf ${DIST_DIR}
-@rm -rf tmp*
-@rm -f ${CACHE_DIR}/aport/${RELEASE_VERSION}/main/${ALPINE_ARCH}/APKINDEX.tar.gz
-@docker rmi ${BUILDER_DOCKER_IMAGE} 1> /dev/null
@echo "### Cleaning done"
mrproper: clean
@echo "### Purging cache..."
-@rm -rf ${CACHE_DIR}
@echo "### Done"
repository-builder: init
@mkdir -p ${CACHE_DIR}/aport/${RELEASE_VERSION}/main/
@rsync -chaz ${CACHE_DIR}/${RELEASE_BASENAME}/apks/ ${CACHE_DIR}/aport/${RELEASE_VERSION}/main/
@tar \
--exclude='.git' \
-czh ./src/repository-builder | docker build -f ./src/repository-builder/repository.Dockerfile \
--build-arg ALPINE_DOCKER_IMAGE=${ALPINE_DOCKER_IMAGE} \
--build-arg REQUIREMENTS_FILE=${REQUIREMENTS_FILE} \
--build-arg BUILDER_USER=${BUILDER_USER} \
--build-arg BUILDER_UID=${BUILDER_UID} \
--build-arg BUILDER_GID=${BUILDER_GID} \
-t ${BUILDER_DOCKER_IMAGE} -
repository: repository-builder
@echo "### Repository..."
@wget --quiet --spider https://alpinelinux.org/ && \
docker run --rm -ti \
-e ALPINE_ARCH=${ALPINE_ARCH} \
-e RELEASE_VERSION=${RELEASE_VERSION} \
-e REQUIREMENTS_FILE=${REQUIREMENTS_FILE} \
-e BUILDER_KEY_BASENAME=${BUILDER_KEY_BASENAME} \
-e BUILDER_UID=${BUILDER_UID} \
-e BUILDER_GID=${BUILDER_GID} \
-v $(PWD)/src/repository-builder/packager.rsa:/root/.abuild/packager.rsa \
-v $(PWD)/src/repository-builder/packager.rsa.pub:/root/.abuild/packager.rsa.pub \
-v $(PWD)/src/repository-builder/abuild.conf:/root/.abuild/abuild.conf \
-v ${CACHE_DIR}/aport:/mirror \
${BUILDER_DOCKER_IMAGE} build-repository \
|| echo "No Internet!!! Skipping repository..."
@echo "### Repository done"
+37
View File
@@ -0,0 +1,37 @@
# Wireguard Road Warrior setup for RaspberryPi 4
Code in this repository produces files for bootable Micro-SD card for RaspberryPi 4. During the boot it creates `entropi_nomap` WIFI access point (hotspot) that clients can connect to. It then encrypts all client traffic through Wireguard tunnel via any known WIFI network in reach. This is supposed to be a headless Alpine Linux router essentially. There is no web admin interface - only SSH access from the client side using public keys (or, you know, physical access with keyboard and monitor attached to the RaspberryPi).
## Requirements
- RaspberryPi
- WIFI over USB dongle
- USB-C cable for powering RaspberryPi (could be plugged directly into a laptop)
- Micro-SD card (I use 2GB and that's plenty big) - Formatted with single FAT32 partition named `entropi`
- Properly set up machine running Wireguard peer instance reachable from the Internet
## Usage
1. Clone this repository
1. Edit `.env` file
1. Create `.vault_password_file` and put a plain text password inside (used for decrypting/encrypting wireguard keys and other stuff)
1. Replace all files listed as `FILES_IN_VAULT` inside the `vault` script with appropriate contents
1. Create known networks files (see below)
1. Insert MicroSD card into your computer and make sure it is mounted under /media/{user}/entropi (edit the Makefile if necessary)
1. Run `make card`
1. Eject the card and use it to boot RaspberryPi (after a minute or two you should see it provides your wifi)
### Known WIFI networks setup
Create `secrets` folder and put plain text files inside named `{KNOWN_WIFI_SSID}.psk` where `{KNOWN_WIFI_SSID}` is the name of each wifi you want to be used to tunnel through (coffee shops, your ISP etc.). Contents of each file needs to be following:
```
[Security]
Passphrase={KNOWN_WIFI_PASSWORD}
AlwaysRandomizeAddress=true
[Settings]
AutoConnect=true
```
All the files will be automatically picked up by the wifi daemon after the RaspberryPi finishes boot process
Executable
+36
View File
@@ -0,0 +1,36 @@
#! /bin/sh
set -eu
# Let's find out if a temporary build directory exists already
BUILD_DIR=$(find . -type d -name "tmp*" -print -quit 2>/dev/null)
# Create it if it doesn't
if ! echo "$BUILD_DIR" | grep -q .; then
BUILD_DIR=$(mktemp --tmpdir=. --directory tmp.build.XXXXXXXXXX)
fi
# Preprocess the dotenv file
./src/esh -o "$BUILD_DIR"/.env ./.env
# Load the contents of the preprocessed dotenv file in order to
# use the values for init stage below
# https://www.shellcheck.net/wiki/SC1090
# shellcheck source=/dev/null
. "$BUILD_DIR"/.env
echo "
RELEASE_BASENAME=alpine-rpi-$ALPINE_VER_MAJOR.$ALPINE_VER_MINOR.$ALPINE_VER_PATCH-$ALPINE_ARCH
RELEASE_VERSION=v$ALPINE_VER_MAJOR.$ALPINE_VER_MINOR
ALPINE_DOCKER_IMAGE=alpine:$ALPINE_VER_MAJOR.$ALPINE_VER_MINOR.$ALPINE_VER_PATCH
wlan0_cidr=$wlan0_base.0/24
wlan0_address=$wlan0_base.1
wlan0_range_start=$wlan0_base.2
wlan0_range_end=$wlan0_base.254
wg0_cidr=$wg0_base.0/24
wg0_address=$wg0_base.12
wg0_gateway=$wg0_base.1" >> "$BUILD_DIR"/.env
echo "$BUILD_DIR"
Executable
+41
View File
@@ -0,0 +1,41 @@
#!/bin/sh
set -e
# First argument is preprocessed .env file supposed to be in tmp.build.XXXXXXXXXX directory
# Let's load it up
. $1
alpine_source() {
find ${CACHE_DIR} -type f -name ${RELEASE_BASENAME}.tar.gz | grep -q ${RELEASE_BASENAME} || \
curl -sSL ${ALPINE_MIRROR}/${RELEASE_VERSION}/releases/${ALPINE_ARCH}/${RELEASE_BASENAME}.tar.gz -o ${CACHE_DIR}/${RELEASE_BASENAME}.tar.gz
mkdir -p ${CACHE_DIR}/${RELEASE_BASENAME}
find ${CACHE_DIR}/${RELEASE_BASENAME} -type d -empty -exec tar xfz ${CACHE_DIR}/${RELEASE_BASENAME}.tar.gz -C ${CACHE_DIR}/${RELEASE_BASENAME} \;
}
tailspin_bin() {
find ${CACHE_DIR} -type f -name tailspin.tar.gz | grep -q tailspin || \
curl -sSL https://github.com/bensadeh/tailspin/releases/download/4.0.0/tailspin-x86_64-unknown-linux-musl.tar.gz -o ${CACHE_DIR}/tailspin.tar.gz
mkdir -p ${CACHE_DIR}/tailspin
find ${CACHE_DIR}/tailspin -type d -empty -exec tar xfz ${CACHE_DIR}/tailspin.tar.gz -C ${CACHE_DIR}/tailspin \;
}
age_bin() {
find ${CACHE_DIR} -type d -name age-src | grep -q age-src || \
git clone https://github.com/wj/age.git ${CACHE_DIR}/age-src
mkdir -p ${CACHE_DIR}/age
find ${CACHE_DIR}/age -type d -empty -exec docker run --rm -v ${CACHE_DIR}/age:/usr/local/bin -e GOBIN=/usr/local/bin/ -v ${CACHE_DIR}/age-src:/usr/src/age -w /usr/src/age golang:1.22-alpine go install ./cmd/age \;
}
mkdir -p secrets
mkdir -p ${CACHE_DIR}/aport
mkdir -p ${CACHE_DIR}/extras
# Second argument is supposed to be name of the functions decalred above
# Let's call it
$2
+14
View File
@@ -0,0 +1,14 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNjcnlwdCBWcXR2SHJWTkIydlB2SHg4
eXYwSHRRIDE4CkNvMG1MTkMxeEZvbkRDd1dSMzFaM3FtOEk1WVhKMUNVQm11T1Vk
YUpoY2cKLS0tIExHOW1ldWh0ZEY0MTdqZFNrR2c4OHpDcUpLNldaNTF3Y3B1L1dy
REt4SXcKzHFocRvKS4/XoF9XqntZJ537DswygYkETQ64qBcBZR45MF5WP/qGmz6p
YZ6S4KOOTJpgibcWht9zzAgaBI1pvGx61lM7StxOoUPpKJGbpx2vxm5T3hljf5GP
1veT6YHwFbVMHBRWNcgFji+ZVloOWC9rhHlF6tjzpY2XlWA+7YBH5OzMnPj8Wysu
JDp7Zx9XJ6Y3vZsLXOWlb36/22hhNRFCvnNA6Mc1RUosbc4PhjMTnh9jeO6sbhGp
kTM9Rq023c8Q8BuKhyJwNEVkOF+l/CvUmm5GGr6+P59/bjvrGseqJeCTESQ0Nlzh
dmm10NRzMKnqHSHUdvtCa5GEoD1NgnNh6cMTCyJr4yIJx6iwcr1G0vuX7iE7THtD
EH/MYowZ1oRPVE60ghWKTiY2bHQCT7VxZX81QVBdIw9LDey4b2MQdsni/2i2sO53
cUqL3CzO559wiCwPm2gULjuS/QmG9rwfMks6wGZX/intyel2o1yqofyx+tdyxQtB
9qBZ1bEsREB4jUeK8uZJYjiJJgSemKs4sxJV0KdpAffryb8=
-----END AGE ENCRYPTED FILE-----
+82
View File
@@ -0,0 +1,82 @@
# style = { fg = "color", bg = "color", italic = false, bold = false, underline = false }
[date]
disabled = true
[date_word] # e.g. "Jan 01", "Mon Feb 28"
disabled = true
[time]
disabled = true
[[keywords]]
words = ['INBOUND']
style = { fg = "cyan", faint = true }
[[keywords]]
words = ['OUTBOUND']
style = { fg = "cyan", faint = false }
[[keywords]]
words = ['DROP']
style = { fg = "red" }
[[keywords]]
words = ['REJECT']
style = { fg = "yellow" }
[[keywords]]
words = ['ACCEPT']
style = { fg = "green" }
[[keywords]]
words = ['TCP']
style = { fg = "blue" }
[[keywords]]
words = ['UDP']
style = { fg = "magenta" }
[[regexps]]
regular_expression = 'MAC=(.*?) '
style = { faint = true }
# IP v4 regexp
[[regexps]]
regular_expression = '(\b\d{1,3})(\.)(\d{1,3})(\.)(\d{1,3})(\.)(\d{1,3}\b)'
style = { fg = "yellow", bold = true }
[[regexps]]
regular_expression = 'SPT=(.*?) '
style = { faint = true }
[[regexps]]
regular_expression = 'DPT=(.*?)$'
style = { bold = true }
[url]
disabled = true
[number]
disabled = true
[ip]
disabled = true
[quotes]
disabled = true
[path]
disabled = true
[uuid]
disabled = true
[pointer]
disabled = true
[key_value]
disabled = true
[process]
disabled = true
Executable
+366
View File
@@ -0,0 +1,366 @@
#!/bin/sh
# vim: set ts=4:
#---help---
# USAGE:
# esh [options] [--] <input> [<variable>...]
# esh <-h | -V>
#
# Process and evaluate an ESH template.
#
# ARGUMENTS:
# <input> Path of the template file or "-" to read from STDIN.
# <variable> Variable(s) specified as <name>=<value> to pass into the
# template (the have higher priority than environment
# variables).
#
# OPTIONS:
# -d Don't evaluate template, just dump a shell script.
# -o <file> Output file or "-" for STDOUT. Defaults to "-".
# -s <shell> Command name or path of the shell to use for template
# evaluation. It must not contain spaces.
# Defaults to "/bin/sh".
# -h Show this help message and exit.
# -V Print version and exit.
#
# ENVIRONMENT:
# ESH_AWK Command name of path of the awk program to use.
# It must not contain spaces. Defaults to "awk".
# ESH_MAX_DEPTH Maximum include depth. Defaults to 3.
# ESH_SHELL Same as -s.
#
# EXIT STATUS:
# 0 Clean exit, no error has encountered.
# 1 Generic error.
# 10 Invalid usage.
# 11 ESH syntax error.
# 12 Include error: file not found.
# 13 Include error: exceeded max include depth (ESH_MAX_DEPTH).
#
# Please report bugs at <https://github.com/jirutka/esh/issues>.
#---help---
set -eu
readonly PROGNAME='esh'
readonly VERSION='0.3.2'
readonly SCRIPTPATH="$0"
AWK_CONVERTER=$(cat <<'AWK'
function fail(code, msg) {
state = "ERROR"
# FIXME: /dev/stderr is not portable
printf("%s: %s\n", line_info(), msg) > "/dev/stderr"
exit code
}
function line_info() {
return FILENAME ? (filenames[depth] ":" linenos[depth]) : "(init)" # (init) if inside BEGIN
}
# IMPORTANT: This is the only function that should print a newline.
function puts(str) {
print(line_info()) > MAP_FILE
print(str)
}
function fputs(str) {
printf("%s", str)
}
function trim(str) {
gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "", str)
return str
}
function read(len, _str) {
if (len == "") {
_str = buff
buff = ""
} else if (len > 0) {
_str = substr(buff, 1, len)
buff = substr(buff, len + 1, length(buff))
}
return _str
}
function skip(len) {
buff = substr(buff, len + 1, length(buff))
}
function flush(len, _str) {
_str = read(len)
if (state == "TEXT") {
gsub("'", "'\\''", _str)
}
if (state != "COMMENT") {
fputs(_str)
}
}
function file_exists(filename, _junk) {
if ((getline _junk < filename) >= 0) {
close(filename)
return 1
}
return 0
}
function dirname(path) {
return sub(/\/[^\/]+\/*$/, "/", path) ? path : ""
}
function include(filename) {
if (index(filename, "/") != 1) { # if does not start with "/"
filename = dirname(filenames[depth]) filename
}
if (!file_exists(filename)) {
fail(12, "cannot include " filename ": not a file or not readable")
}
if (depth > MAX_DEPTH) {
fail(13, "cannot include " filename ": exceeded maximum depth of " MAX_DEPTH)
}
buffs[depth] = buff
states[depth] = state
filenames[depth + 1] = filename
depth++
init()
while ((getline buff < filename) > 0) {
if (print_nl && state != "COMMENT") {
puts("")
}
process_line()
}
end_text()
close(filename)
depth--
buff = buffs[depth]
state = states[depth]
}
function init() {
buff = ""
linenos[depth] = 0
print_nl = 0
start_text()
}
function start_text() {
puts("")
fputs("printf '%s' '")
state = "TEXT"
}
function end_text() {
if (state != "TEXT") { return }
puts("' #< " line_info())
state = "UNDEF"
}
function process_line() {
print_nl = 1
linenos[depth]++
while (buff != "") {
print_nl = 1
if (state == "TEXT" && match(buff, /<%/)) {
flush(RSTART - 1) # print buff before "<%"
skip(2) # skip "<%"
flag = substr(buff, 1, 1)
if (flag != "%") {
end_text()
}
if (flag == "%") { # <%%
skip(1)
fputs("<%")
} else if (flag == "=") { # <%=
skip(1)
fputs("__print ")
state = "TAG"
} else if (flag == "+") { # <%+
if (!match(buff, /[^%]%>/)) {
fail(11, "syntax error: <%+ must be closed on the same line")
}
filename = trim(substr(buff, 2, match(buff, /.-?%>/) - 1))
skip(RSTART)
include(filename)
state = "TAG"
} else if (flag == "#") { # <%#
state = "COMMENT"
} else {
state = "TAG"
}
} else if (state != "TEXT" && match(buff, /%>/)) {
flag = RSTART > 1 ? substr(buff, RSTART - 1, 1) : ""
if (flag == "%") { # %%>
flush(RSTART - 2)
skip(1)
flush(2)
} else if (flag == "-") { # -%>
flush(RSTART - 2)
skip(3)
print_nl = 0
} else { # %>
flush(RSTART - 1)
skip(2)
}
if (flag != "%") {
start_text()
}
} else {
flush()
}
}
}
BEGIN {
FS = ""
depth = 0
puts("#!" (SHELL ~ /\// ? SHELL : "/usr/bin/env " SHELL))
puts("set -eu")
puts("if ( set -o pipefail 2>/dev/null ); then set -o pipefail; fi")
puts("__print() { printf '%s' \"$*\"; }")
split(VARS, _lines, /\n/)
for (_i in _lines) {
puts(_lines[_i])
}
init()
}
{
if (NR == 1) {
filenames[0] = FILENAME # this var is not defined in BEGIN so we must do it here
}
buff = $0
process_line()
if (print_nl && state != "COMMENT") {
puts("")
}
}
END {
end_text()
}
AWK
)
AWK_ERR_FILTER=$(cat <<'AWK'
function line_info(lno, _line, _i) {
while ((getline _line < MAPFILE) > 0 && _i++ < lno) { }
close(MAPFILE)
return _line
}
{
if (match($0, "^" SRCFILE ":( line)? ?[0-9]+:") && match(substr($0, 1, RLENGTH), /[0-9]+:$/)) {
lno = substr($0, RSTART, RLENGTH - 1) + 0
msg = substr($0, RSTART + RLENGTH + 1) # v-- some shells duplicate filename
msg = index(msg, SRCFILE ":") == 1 ? substr(msg, length(SRCFILE) + 3) : msg
print(line_info(lno) ": " msg)
} else if ($0 != "") {
print($0)
}
}
AWK
)
readonly AWK_CONVERTER AWK_ERR_FILTER
print_help() {
sed -En '/^#---help---/,/^#---help---/p' "$SCRIPTPATH" | sed -E 's/^# ?//; 1d;$d;'
}
filter_shell_stderr() {
$ESH_AWK \
-v SRCFILE="$1" \
-v MAPFILE="$2" \
-- "$AWK_ERR_FILTER"
}
evaluate() {
local srcfile="$1"
local mapfile="$2"
# This FD redirection magic is for swapping stdout/stderr back and forth.
exec 3>&1
{ set +e; $ESH_SHELL "$srcfile" 2>&1 1>&3; echo $? >>"$mapfile"; } \
| filter_shell_stderr "$srcfile" "$mapfile" >&2
exec 3>&-
return $(tail -n 1 "$mapfile")
}
convert() {
local input="$1"
local vars="$2"
local map_file="${3:-"/dev/null"}"
$ESH_AWK \
-v MAX_DEPTH="$ESH_MAX_DEPTH" \
-v SHELL="$ESH_SHELL" \
-v MAP_FILE="$map_file" \
-v VARS="$vars" \
-- "$AWK_CONVERTER" "$input"
}
process() {
local input="$1"
local vars="$2"
local evaluate="${3:-yes}"
local ret=0 tmpfile mapfile
if [ "$evaluate" = yes ]; then
tmpfile=$(mktemp)
mapfile=$(mktemp)
convert "$input" "$vars" "$mapfile" > "$tmpfile" || ret=$?
test $ret -ne 0 || evaluate "$tmpfile" "$mapfile" || ret=$?
rm -f "$tmpfile" "$mapfile"
else
convert "$input" "$vars" || ret=$?
fi
return $ret
}
: ${ESH_AWK:="awk"}
: ${ESH_MAX_DEPTH:=3}
: ${ESH_SHELL:="/bin/sh"}
EVALUATE='yes'
OUTPUT=''
while getopts ':dho:s:V' OPT; do
case "$OPT" in
d) EVALUATE=no;;
h) print_help; exit 0;;
o) OUTPUT="$OPTARG";;
s) ESH_SHELL="$OPTARG";;
V) echo "$PROGNAME $VERSION"; exit 0;;
'?') echo "$PROGNAME: unknown option: -$OPTARG" >&2; exit 10;;
esac
done
shift $(( OPTIND - 1 ))
if [ $# -eq 0 ]; then
printf "$PROGNAME: %s\n\n" 'missing argument <input>' >&2
print_help >&2
exit 10
fi
INPUT="$1"; shift
if [ "$INPUT" != '-' ] && ! [ -f "$INPUT" -a -r "$INPUT" ]; then
echo "$PROGNAME: can't read $INPUT: not a file or not readable" >&2; exit 10
fi
# Validate arguments.
for arg in "$@"; do
case "$arg" in
*=*) ;;
*) echo "$PROGNAME: illegal argument: $arg" >&2; exit 10;;
esac
done
# Format variables into shell variable assignments.
vars=''; for item in "$@"; do
vars="$vars\n${item%%=*}='$(
printf %s "${item#*=}" | $ESH_AWK "{ gsub(/'/, \"'\\\\\\\''\"); print }"
)'"
done
export ESH="$0"
if [ "${OUTPUT#-}" ]; then
tmpfile="$(mktemp)"
trap 'rm -f -- "$tmpfile"' EXIT HUP INT TERM
process "$INPUT" "$vars" "$EVALUATE" > "$tmpfile"
cat "$tmpfile" > "$OUTPUT"
else
process "$INPUT" "$vars" "$EVALUATE"
fi
+207
View File
@@ -0,0 +1,207 @@
#!/bin/sh
set -ex
SDCARD_MEDIA=$(find /media -name *.apkovl.tar.gz -exec dirname {} \; -quit)
copyfile() {
OWNER="$1"
PERMS="$2"
SOURCE="$3"
DEST="$4"
cp -f "$SOURCE" "$DEST"
chown "$OWNER" "$DEST"
chmod "$PERMS" "$DEST"
}
__setup_loopback_interface()
{
cat <<-EOF > /etc/network/interfaces
auto lo
iface lo inet loopback
EOF
}
__setup_eth_interface()
{
cat <<-EOF >> /etc/network/interfaces
auto <%= $eth0 %>
iface <%= $eth0 %> inet dhcp
hostname <%= $hostname %>
EOF
}
__setup_integrated_wireless_interface()
{
cat <<-EOF >> /etc/network/interfaces
auto <%= $wlan0 %>
iface <%= $wlan0 %> inet static
hostname <%= $hostname %>
pre-up sysctl -w net.ipv4.ip_forward=1
pre-up iwctl device <%= $wlan0 %> set-property Mode ap
pre-up iwctl ap <%= $wlan0 %> start-profile <%= $ssid %>
post-up iptables -t nat -A POSTROUTING -s <%= $wlan0_cidr %> -j MASQUERADE
pre-down iptables -t nat -D POSTROUTING -s <%= $wlan0_cidr %> -j MASQUERADE
EOF
}
__setup_external_wireless_interface()
{
cat <<-EOF >> /etc/network/interfaces
auto <%= $wlan1 %>
iface <%= $wlan1 %> inet dhcp
hostname <%= $hostname %>
EOF
}
# Uncomment for alternative:
#
# ALPINE_MIRROR=https://mirror.fit.cvut.cz/alpine
__setup_network_repositories()
{
cat <<-EOF > /etc/apk/repositories
${SDCARD_MEDIA}/apks
${SDCARD_MEDIA}/extras
<%= $ALPINE_MIRROR %>/<%= $RELEASE_VERSION %>/main
<%= $ALPINE_MIRROR %>/<%= $RELEASE_VERSION %>/community
EOF
}
__setup_local_repositories()
{
cp ${SDCARD_MEDIA}/<%= $BUILDER_KEY_BASENAME %>.rsa.pub /etc/apk/keys
chmod 644 /etc/apk/keys/<%= $BUILDER_KEY_BASENAME %>.rsa.pub
cat <<-EOF > /etc/apk/repositories
${SDCARD_MEDIA}/apks
${SDCARD_MEDIA}/extras
EOF
apk update
}
__setup_user_account()
{
mkdir -p /root/.ssh
cp ${SDCARD_MEDIA}/authorized_keys /root/.ssh/authorized_keys
chown -R root:root /root/.ssh
cat <<-EOF >> /root/.profile
tail -f -n 60 /var/log/messages
EOF
}
__setup_time()
{
rc-service chronyd stop
cat <<-EOF > /etc/chrony/chrony.conf
initstepslew 60 <%= $ROUTER_NTP_PRIMARY %> <%= $ROUTER_NTP_SECONDARY %>
driftfile /var/lib/chrony/chrony.drift
rtcsync
cmdport 0
server <%= $ROUTER_NTP_PRIMARY %> iburst
server <%= $ROUTER_NTP_SECONDARY %> iburst
makestep 60 10
EOF
rc-service chronyd start
}
__setup_profiles()
{
cat <<-EOF >> /etc/profile
alias l="tail -f -n 60 /var/log/messages"
alias k="tail -f -n 60 /var/log/kern.log | tspin"
alias ll="ls -la"
alias ..="cd .."
EOF
}
__setup_randomness()
{
rc-service haveged start
}
__setup_logging()
{
copyfile root:root 0700 ${SDCARD_MEDIA}/tspin /usr/bin/tspin
mkdir -p /root/.config/tailspin
copyfile root:root 0700 ${SDCARD_MEDIA}/config.toml /root/.config/tailspin/config.toml
mkdir -p /etc/rsyslog.d
copyfile root:root 0700 ${SDCARD_MEDIA}/logpattern.conf /etc/rsyslog.d/logpattern.conf
copyfile root:root 0700 ${SDCARD_MEDIA}/rsyslog.conf /etc/rsyslog.conf
rc-service --list | grep rsyslog && \
rc-service syslog stop && \
rc-service rsyslog start
}
__setup_firewall() {
modprobe -v ip_tables
modprobe -v iptable_nat
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.conf.all.forwarding=1
iptables -A INPUT -j LOG --log-prefix 'fw: INBOUND '
iptables -A OUTPUT -j LOG --log-prefix 'fw: OUTBOUND '
/etc/init.d/iptables save
rc-service iptables start
}
__setup_wireless_client() {
mkdir -p /var/lib/iwd/ap/
copyfile root:root 0644 ${SDCARD_MEDIA}/main.conf /etc/iwd/main.conf
copyfile root:root 0644 ${SDCARD_MEDIA}/NUMERI_AC11.psk /var/lib/iwd/NUMERI_AC11.psk
copyfile root:root 0644 ${SDCARD_MEDIA}/robusta_nomap.psk /var/lib/iwd/robusta_nomap.psk
copyfile root:root 0644 ${SDCARD_MEDIA}/hotspot.conf /var/lib/iwd/ap/<%= $ssid %>.ap
copyfile root:root 0700 ${SDCARD_MEDIA}/watchdog.sh /etc/wireguard/watchdog.sh
rc-service dbus start
rc-service dbus start
rc-service iwd start
}
/sbin/setup-hostname <%= $hostname %>
/sbin/setup-timezone -z <%= $ROUTER_TIMEZONE %>
__setup_local_repositories
apk add `cat ${SDCARD_MEDIA}/<%= $REQUIREMENTS_FILE %>`
__setup_logging
__setup_randomness
__setup_profiles
__setup_user_account
__setup_loopback_interface
__setup_eth_interface
__setup_integrated_wireless_interface
__setup_external_wireless_interface
__setup_wireless_client
__setup_firewall
rc-service networking start
mkdir -p /etc/wireguard
copyfile root:root 0600 ${SDCARD_MEDIA}/wg0.conf /etc/wireguard/wg0.conf
ln -s /etc/init.d/wg-quick /etc/init.d/wg-quick.wg0
# rc-service wg-quick.wg0 start
__setup_time
/etc/wireguard/watchdog.sh
__setup_network_repositories
+12
View File
@@ -0,0 +1,12 @@
[General]
DisableHT=true
[Security]
Passphrase=<% cat src/wifi-password.txt %>
[IPv4]
Address=<%= $wlan0_address %>
Gateway=<%= $wlan0_address %>
Netmask=255.255.255.0
DNSList=<%= $wg0_gateway %>
IPRange=<%= $wlan0_range_start %>,<%= $wlan0_range_end %>
+1
View File
@@ -0,0 +1 @@
$template logpattern,"%timegenerated:1:19:date-rfc3339% %msg:F,32:3% %msg:R,ERE,1,BLANK:(IN=[a-zA-Z0-9]*)--end% %msg:R,ERE,1,BLANK:(OUT=[a-zA-Z0-9]*)--end% %msg:R,ERE,1,BLANK:(SRC=[a-zA-Z0-9\.]*)--end% %msg:R,ERE,1,BLANK:(DST=[a-zA-Z0-9\.]*)--end% %msg:R,ERE,1,BLANK:(PROTO=[a-zA-Z0-9]*)--end% %msg:R,ERE,1,BLANK:(SPT=[0-9]*)--end% %msg:R,ERE,1,BLANK:(DPT=[0-9]*)--end%\n"
+41
View File
@@ -0,0 +1,41 @@
# Note: The lines starting with # are ignored. To enable any of the
# configuration options below, remove # from the beginning of a respective line.
# this file is not distributed upstream as of iwd 1.0 version
# It is created as transitional config from latest version
# Please read iwd.config(5), iwd.network(5), iwctl(1), iwmon(1) before setting
# these parameters below
# main.conf format is changed with iwd 1.3 release
#[EAP]
#mtu=1400
#[General]
#EnableNetworkConfiguration=True
#ControlPortOverNL80211=True
#RoamThreshold=-70
#[Network]
#NameResolvingService=resolvconf
#[Scan]
# DisablePeriodicScan=false
# DisableRoamingScan=false
#[Blacklist]
#[Rank]
# BandModifier5Ghz=1.0
[General]
EnableNetworkConfiguration=True
Country=CZ
[Network]
EnableIPv6=false
NameResolvingService=resolvconf
+1
View File
@@ -0,0 +1 @@
PACKAGER_PRIVKEY="/root/.abuild/packager.rsa"
+74
View File
@@ -0,0 +1,74 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNjcnlwdCBrbk9nejJwcDF6WmdHaEN2
N0JHT1BBIDE4CndHZnVkUU5MUmhxT09kZXZ0V1Vwei9LRVFER1E1aktqT0VSaXUx
c043U3MKLS0tIGdLL3B4a0lhNXVGVXZyU01CQ09Rc2RyUlpFVVVoZXBSVlRBWlRW
QXRUb1kKULpkyDn3NpjI2IO/iehEDS1TxAPh9leKHNSNTeHvWnPMHeeUZbXZd9+O
DzInQbNT7x+g+eFBc2hAvMBm04OuP0Z0f2vuk6oUIjFSwbaRAkh9QsYKkglkUCEA
cUHu2xdl58IL51LROyHjAztxtQUTekWWh7l/PC60xWTXAWLeGZFBFAfcH25isvIF
EUfW77+HoUoYLZrorN60xF0QUFsQKqaCpT7KBxPw1Mh3NRdmC9MJbUd5A+v48ADh
/QFmg5MCofL3K7EIaKJiptAl2AQVbGKAEBbsqEMM0IwqBBphZm4Kp4o5xMBEFQeQ
fKmp+1Mm1jlX3388M8lkl3ugwOQ5Le9J6arZPP6VCbUdPP4vsYjykUjLQly6ihDe
O/u+MV3bKZErygZ8FNFQr3wQmSim60ys8nKpz6NH393F+lY69Y1TAFfx39GBI6li
7ZrzwgteYa/HTW8vcIfVxwKYHkgocdVOtuWjgG579ntPzieIYxTaj4win0BzkGaH
+5Z/z7tMTyUd7ISkXnQwwUomrkHp9FLj3AGgbjC7hp9WqZ/cgTysiRGGmrI6H4iG
xRsXAsB7VsHEuGQe+qvF2OYI7LUKcBBrmEDJXJ1cTJxf7qwUf/+dmiHeVuwOaozW
lxGDbZ8KdBuxfW28WMoH3gHq1jonOSwiPYhWfb/wtM3NIZPpZXAXjujUACIoaF/e
ZFmPn5N1nrefon3LaE53GusKuXpobKL+CY8Zkw2cPcCJW6E0IqanFD1waphYK1f2
hkihZR4c8Jo5aWLlSkljFojo4n7+Xmtwcep/LKYDeXXgu1+amT9R/5+S081q2QzF
+jJotlojm2hu+O5Q7LgjuMgIuZzMa8rNYVAaOTZuxG1bu6JwHUjoUTdzrzQq3KeI
oQc16lWdxI5g+2tisyRTyPOVN6y5kAfG4ZkUqMj2tIhCwW615G1ywXvvLQUoLshl
FoGX/ITldWS+oQU/OKUPpGa8VZysM3C0XRWnwat+ChVQnIuVxkuAFXAC0oODpLnL
MI424fjM6/5YOgVmkpSd8E/+8oXgeDpXXAx7+Fo5Ngpd69EUNs4w4nK5huAWsg7m
QCWXL02xHP6iiPW7wKyegCLgMAFeVc2zcC6n+77Qlz9G7onww5+0Lnz687qz65FI
4SkqYfM7/1unmBDHOJlsG71tYMr2nbCUSisDWJdjNdmWiSH7RCNN42phLdQss9Kp
whIfCUpCBtBw6vPy4Bc318L/H0Bq4TpQWFdB/OVCyvUDNGbK3KAKLRyvsDif/Z6A
CffZdbxn4phtueK1vZQQvodGF4SgcNdd2AdVDyYxL6tnUs+EWAoxnH0MixlCxnKO
PNlyiYsiW/YdjeFZygUM+qdLYiMpxonhsjBbKbqCdddP2ccfArnxH7BnnILhbjCD
tKuihrblOWpiH0S3UkAx3HuCh/5q0fCa5MkL6o+I5bN/V/V//iGtr9FRPDEz6To4
p/bTbq1CGLHci9mUJkdkU+Y8RW+tbDTpgcNHRc0LwiVdsc+bjVFDIs2kMAH6C/lz
7toauF7uGCmdBapZHJMwAZKeBYlXEQiR6NxcWEbUSPr7xVtRrwxQBATKFn6N+C/A
1A4Oiq87409Q9w/q8PFAQhBeK3tNzOb+6Sg61kzeZv5IMYu2cuKCTTMfSGxZyzCJ
ReGNHoye4kQ0w0TwpYnmYH898rnuKGLYgTm9sqg/7DBFG4Dez1YrOO6Rnr3XgwHb
S49HN1QGt//6Trv3orR6bjqn+ehEkFtWQk827cOsUtPAzw9Y2gmKnNOfUUo6pyuX
PoDTxg8L1Bv1zZAQJlwzH0FJrVjEYb5Eq4KOVRgclXQ1Qlm75YO5v7IJpiN/tkVL
olqAHnk7iXWcjMW9Zazv8qPg0S5NkKtYdPQg756Y54K/uhTvtpI0N9JHNRysLWL7
diGvtJDkidA0frQ1P2Em2ABHOKc5ObKlt1sgWofjE+zGKgt46oAC/0erTrpyH8jt
lf4gFL8nUHMWxV3fl8rfNaS7a2Ti3qP6g/BYyLbvxf6xY+Ey/oqc+BqSvU1kcUdc
hpYmQ+eRwDKXHJvFzHNedG/I9tDIso/achpuxEot3V5+bT0TnTL54cR5y+AE0diz
frysWuMKxSGDzdMPsrAECK52J03J512wCEKAyjl4jZImIgfAb7dGVwPyRf9jbpXD
u3bOJ5j6hoMwtEPKS5Pi0WebUVoJfWd1GuZB0tMhsVQOvggnh+zuN5X1FwEzxfDq
mXufznwj+Qoi5sqQErD/uDIYISPryR81EvprkLKbq+pPuEMea2s5F1wjz3iBgqZT
vjeevrWJhR/hDgJsNt1Sq5lQj6xqAi6Tdfl1fG663ocxmMSPXQiH1Wi/R9A383Jk
vilvpAfvuAqdeLTwNi1Eo43qVwenmK4kZ2dbvJ5yJ0jq+pB4KgA5o3AAhCSVHhK8
UYyZprNSE61N4rggxJsc6PBp83v/ZGqCe0owLrSIkK8BKJ/ANXuj6X4aLWdZkRFC
vzhGQxCCOpgGI5gWR7rdQE3UimnvvydoT4xnTLylHrhR0/51TLyz+FgHlhUSutnu
h6miERLXt52oDYKxvFgMPButZMe1plafKx3xsHgYcEyA7/xLDLRGCK82E7F+8wvo
Wcng71kfww2LnSOKyd8FhulBYcFLWZs9XgEdg5rWLg32q1GyHzl+unxFNh7FB27E
1V7+ZGEbEEJSBrNCFKNqCqcm8K8HkGDmNAgcMQtt2Ho1kS+4PhdcBKfWI7iLfLQX
9Tf7gsjLYLZhfsVlEnUVv/sZLxkJTbyNoOEEiQdKqcqifoqf/dKop3DP3SaFbAB7
hthiQ+99M6ML20nIL3/xGeLfNIDZcgqOCEtBDQ2y3l4aF5UQLIj+hntMKBBOZ9wI
VIROnx48U/hEIyuFEuGwPdaC0Te15OuMq6o6QWWf2mfXOa2OmZuoD1FHFG4BCFNt
GTZRq13x75C4mP+vEbwPg5XaG7NtJMwMWFd5BsjFFezRa3V6YJ+YYG7mB5UvWiiL
oziBxrUhP8qcsA1uVWYvKPh42Lu3ClV0iPst6b+7rC1ztWu6npmvaAiuP1ELrRKM
JnrFGh26/n8Tqs4cXfOu5+5E1a1f2EuPSPlu/8uQUDYbLETmF+dUOMbggX3W4YP7
rv/cqi9FwO7eq9RDWnwXkatN8uM57rxOPqZ3DRtVojdsacvuNS5lmX0V+8fBESNw
mSlwA/bvfiHXUZEo29waFaZxTb0Qbwje4UfFVW2YuYXN2TWY/3a1nMBUwTo8bOW2
3abvIjmrVKYXnmTq4VBeYuAV/9++mMqzJcD+OTYFAxzP+QKbO6B4w9606vKBpZNz
JnZsL9rQF4EXUNTDZ/BRkFreP0l2rBsCb74PkFvF04iUzrQlb+K7+ZvaX1GpiOYO
pDArKFAw8v1pwwjjEwlak+JCNg/46iwKZnEID5iAZFtL3hTsSAiXTa+BXd7BYFZ1
RsmcLu6EhCddBMq6wOTJ+pyRgLmGU9+id6nQTZ5VyhhV8uNXCjt1Q6uKuEQbp5QJ
UZOHjFQDPyXQ2KrHEmiwYql+zbGuYEQZfgT9x36+mWHLocGUMSPtJdvh1G/X5Nhq
rQKLg12adc1o2xqerQUrV6JgWOv5s2jDKQakyRXtNunLFVtzhbKfGsB1uxEtkL+L
/utFv0Tq/QE1D+ab3E7Skw6mjONn2iZKxkghU1xdiO0Vc7xVdPB+Ev9HW446a5+M
z6rdgTbnvgVmHov3pQuQ6j7ceuu9evvlJ+ewxBxIoLqWDl06kKFmEOMUFSgLKKKk
+tuS924mD3CShklHlc+fm2yLGSU4H4CMKkL0ZcgilB0DCTP0xE10r2/elzDR1YiS
xGto/ztrdEmGY50znWtx6TLPoNGqdfTU223k7dH4uKzxDFMjYFApUuAsFiNuIJ2X
EIVPD8hv6kXIncmonh4Rb5UJIpPwVrl42iY+IRcejIf+/UWN+SAy280lvLhMErsM
ClDCeHq4mDIFK0f6+Q6LKw7vU/vHK7wbDJFX2youaJVFZUE9CuPRkBWztj+LgAPA
c0A/YFSZ0j3IZraO3nsjXYlfDN5kvN2Y5e2APCXQafQRWGudfBN1XuHbPSNgsX3F
ZnAncBvKFFqh3KYwTLaWScpxkfB5xo/s+lU8GPXhLYDGXfbXgdUtSSxPbea28j4K
tIVB5jHAwSjZF0hw1717XlndYowFnxHmLlHh83EHXKbAraV6iNdpEmF1reaHJiRs
dscH1q6mIsV1tAWbD62BDA1jZW608Y3U4O2UK7L/dxb958UCcuZlpmPpJ3WhF+1s
qs50HrGTYxC2dMUHWCqXZMAxNnIYxwCJrK0hl67/bnEancPctmvW2rJ9AEmDno63
ThPHxjeMrP3F9WQLmZlc0IgCd0leBWBoRNieNPOAWib0IHgHBNQ7bs9y
-----END AGE ENCRYPTED FILE-----
+23
View File
@@ -0,0 +1,23 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNjcnlwdCAvS2hSWUIyMGRWb1JiSWZk
cGtDeWNnIDE4CkhLNlhkV1NNZTNKRGFEUGQ1MnRWMkpobzh0dnZuMXRlVWZhOCtF
cklmR1kKLS0tIFdmMUlRMWo0YVF6WWFLNFR6NEttMFhmQVh6c1V5Slh6M1dOZllY
WGs3WWcKsYHS7ureliLncEfsmDd+XOOYNjZybEDgy2FrfhzPLLGmIhItQP9xVuRp
ur7XwemHDZ6WY53DB27gSZI0zsCKivgLfrajOAQZoQtkR4A4TKxd9nQBhtCnoS+I
jrIJXh60D/5WxCHRH2MkvgoHWPEK2KfXcNorUXuuU3v6uYigEZik0H2QSubWFQLP
l349pTFvOZFXaSmj4Z2GBH8pZ206/7FhMZVdEuTx63T+HKNku4OS4e7/6M+kImn2
0wvOQsKQWvBTFYeez8rtEeUMZWYUD4iaPIhZBw3jFICL0WC5ujiPJ61tyN67aa+d
igdT2VZ3PU0G6VOYRU+9Q4fU1A0mB2ZeOfhzQygCqe84tac4rCLmXpON03r5mAPm
khcWaqrMv4MZTApqyrvfSY/Nh1adr3hZjefTWbWuNOxCC3P3SL54MvxlMwJOtlhD
najYWdKIHeBbrMmZH3zw9g6Kh18ZnbMYVdq3zLxbpcKw71NVP8W1OfA6OcHVqWZy
ydyVPSRWRLzjxwDPmt+CYL3cM6H1jNoD+0xTk+QgFrmUMySvkjrnXodHTuyKKcYo
zud7DhtCRk6hueaXRauMdEkCoXDn2nOUxekgSLjlt1l1fYPmQliRijXxTnv9lNTg
3kovw+vUsl2RIUqMDT4dgs11oYe4gndkCMqYuM7tXNPTjRkWBF3UOp1LxJ9QH/A0
TbPTHtBPCj0Jc/0+TN0nDkllf2RSMqu8AISyNkxSptdgsMfnMxxfb4Ec7rsdbKu9
HTAaudA0TgdDa65PU2MFAHJbZGjZBtDwchNxtegaXjrNKjjarSkxSqBBpYoiRf5u
IE236DyyqF9QviD51dEgZzY333FFmOuIidDIYbYFSkLUQAVfrrF8HCqsu5/VFj2q
ZruHPOa6oFBuDeXGEOppvw1yarWHroygj7Ab01CxFCwMKmsNTM+AMi5K69ZatEB1
a7L8MLk7cQiO1DgI7ysJZ9uPTbnd7Q/+osSO2tFLjstFWvGXRRutfJLDOet2+HhF
IO9ZrjpbY+lDvU4105LVDTOq6fwSuDQ2or/uRZiDPBzLwvcf1LuzTeukKV+saIt2
77oRYixJFeHjfSHHz9Ue0F7YIyYSJg==
-----END AGE ENCRYPTED FILE-----
@@ -0,0 +1,17 @@
# syntax = docker/dockerfile:1
ARG ALPINE_DOCKER_IMAGE
FROM $ALPINE_DOCKER_IMAGE
ARG REQUIREMENTS_FILE
ARG BUILDER_USER
ARG BUILDER_UID
ARG BUILDER_GID
RUN /usr/sbin/addgroup -g $BUILDER_GID $BUILDER_USER && \
/usr/sbin/adduser -D -g "" $BUILDER_USER -u $BUILDER_UID -G $BUILDER_USER
RUN mkdir /root/.abuild
RUN apk add --no-cache abuild
ADD src/repository-builder/$REQUIREMENTS_FILE /tmp/$REQUIREMENTS_FILE
ADD src/repository-builder/repository.build.sh /bin/build-repository
+27
View File
@@ -0,0 +1,27 @@
#!/bin/sh
set -e
# 1>/dev/null
APKS_TO_INSTALL=`cat /tmp/$REQUIREMENTS_FILE`
apk fix --arch $ALPINE_ARCH
apk update --arch $ALPINE_ARCH --allow-untrusted
apk fetch --allow-untrusted --recursive --link --arch $ALPINE_ARCH --output /mirror/$RELEASE_VERSION/main/$ALPINE_ARCH $APKS_TO_INSTALL
if ! ls /mirror/$RELEASE_VERSION/main/$ALPINE_ARCH/*.apk >& /dev/null; then
return 1
fi
chown -R $BUILDER_UID:$BUILDER_GID /mirror
echo /mirror/$RELEASE_VERSION/main > /etc/apk/repositories
# abuild-keygen -a
cp /root/.abuild/$BUILDER_KEY_BASENAME.rsa.pub /etc/apk/keys
apk index -vU -d $RELEASE_VERSION --allow-untrusted --rewrite-arch $ALPINE_ARCH -o /mirror/$RELEASE_VERSION/main/$ALPINE_ARCH/APKINDEX.tar.gz `ls /mirror/$RELEASE_VERSION/main/$ALPINE_ARCH/*.apk`
abuild-sign -k /root/.abuild/$BUILDER_KEY_BASENAME.rsa /mirror/$RELEASE_VERSION/main/$ALPINE_ARCH/APKINDEX.tar.gz
chown -R $BUILDER_UID:$BUILDER_GID /mirror
apk update --arch $ALPINE_ARCH --allow-untrusted
+12
View File
@@ -0,0 +1,12 @@
busybox-extras
busybox-extras-openrc
chrony
haveged
rsyslog-openrc
rsyslog
less
iptables
wireguard-tools
iwd
mc
nano
+96
View File
@@ -0,0 +1,96 @@
# rsyslog configuration file
#
# For more information see /usr/share/doc/rsyslog-*/rsyslog_conf.html
# or latest version online at http://www.rsyslog.com/doc/rsyslog_conf.html
# If you experience problems, see http://www.rsyslog.com/doc/troubleshoot.html
#### Global directives ####
# Sets the directory that rsyslog uses for work files.
$WorkDirectory /var/lib/rsyslog
# Sets default permissions for all log files.
$FileOwner root
$FileGroup adm
$FileCreateMode 0640
$DirCreateMode 0755
$Umask 0022
# Check config syntax on startup and abort if unclean (default off).
#$AbortOnUncleanConfig on
# Reduce repeating messages (default off).
#$RepeatedMsgReduction on
#### Modules ####
# Provides --MARK-- message capability.
module(load="immark")
# Provides support for local system logging (e.g. via logger command).
module(load="imuxsock")
# Reads kernel messages.
module(load="imklog")
#### Config files ####
# Include all config files in /etc/rsyslog.d/.
include(file="/etc/rsyslog.d/*.conf" mode="optional")
#### Rules ####
# Log all kernel messages to kern.log.
# Log anything (except mail) of level info or higher.
# Don't log private authentication messages!
# NOTE: The minus sign in front of filename disables buffer flush.
*.info;authpriv.none;cron.none;kern.none;mail.none -/var/log/messages
# The authpriv file has restricted access.
authpriv.* /var/log/auth.log
# Log all the mail messages in one place.
mail.* -/var/log/mail.log
# Log cron stuff.
cron.* -/var/log/cron.log
# Everybody gets emergency messages.
*.emerg :omusrmsg:*
# Log all kernel messages to the console.
# Logging much else clutters up the screen.
#kern.* /dev/console
### Examples ####
# Send all logs to remote syslog via UDP.
# An on-disk queue is created for this action. If the remote host is
# down, messages are spooled to disk and sent when it is up again.
#*.* action(
# type="omfwd"
# target="192.168.0.1"
# port="514"
# protocol="udp"
# queue.filename="fwdRule1" # unique name prefix for spool files
# queue.type="LinkedList"
# queue.maxDiskSpace="256m"
# queue.saveOnShutdown="on"
# action.resumeRetryCount="-1"
# action.resumeInterval="30"
#)
# Receive messages from remote host via UDP
# for parameters see http://www.rsyslog.com/doc/imudp.html
#module(load="imudp") # needs to be done just once
#input(
# type="imudp"
# port="514"
#)
:msg, contains, "fw:" /var/log/kern.log;logpattern
& stop
kern.* /var/log/kern.log
+10
View File
@@ -0,0 +1,10 @@
disable_splash=1
# Disable Wi-Fi and Bluetooth to save power
# dtoverlay=disable-wifi
dtoverlay=disable-bt
# This will use more power but lower
# overall system latency, which is fairly desirable for a
# system acting as a router.
force_turbo=1
+37
View File
@@ -0,0 +1,37 @@
#!/bin/sh
current_process=$$
tries=3
some_time=5
kill_child_processes() {
for dir in /proc/[0-9]*; do
process_id=$(cat ${dir}/stat | awk '{print $4}')
child_id=$(cat ${dir}/stat | awk '{print $1}')
if [ ${process_id} -eq $1 ]; then
kill -9 ${child_id}
fi
done
}
trap "kill_child_processes ${current_process} ; kill -9 ${current_process}" SIGTERM SIGINT SIGHUP
while [ $tries -ge 1 ]
do
if ! ping -q -c 1 10.0.22.1 > /dev/null ; then
until ntpd -n -q -p $(nslookup tik.cesnet.cz 1.1.1.1 | grep 'Address' | tail -1 | cut -d ' ' -f 2)
do
rc-service wg-quick.wg0 stop
logger -t ntp_sync "Trying to sync time..."
sleep $some_time &
wait $!
done
rc-service wg-quick.wg0 status | grep "started" || rc-service wg-quick.wg0 start
sleep $some_time &
wait $!
fi
sleep $some_time &
wait $!
tries=$(( $tries - 1 ))
done
exit 0
+12
View File
@@ -0,0 +1,12 @@
[Interface]
ListenPort = <%= $wg_port %>
PrivateKey = <%= $(cat src/wireguard.private.key) %>
Address = <%= $wg0_address %>
DNS = <%= $wg0_gateway %>
MTU = 1280
[Peer]
PublicKey = <%= $(cat src/wireguard.public.key) %>
Endpoint = <%= $wg_server %>:<%= $wg_port %>
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
+6
View File
@@ -0,0 +1,6 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNjcnlwdCAweWZSMk14YkN6NjZibmpN
ZjRXSkxnIDE4CitRZVR4aDZJZ21ZYVY0RWxvdTE4OVVhVXE3RVRmRUtYRlBRRm9Q
ZUFoTWcKLS0tIFg1S0pOOEt3NGlUYTRTeXVwTS9LaDhmdDdsNFpQRnpycGhXeCtD
S0FYN0kK7VkM5XZAPBGpnZy0imULXgM7M0ZG0CcxPoX/IjqBdpx99WJOVc3HReY=
-----END AGE ENCRYPTED FILE-----
+7
View File
@@ -0,0 +1,7 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNjcnlwdCBSMXRlOCtyRmlzZ3pRc2lT
eTBKWVJRIDE4Ckc2dmZVdTZjSjg3L1NzY2UzTCtDcFdFU3Z2NmF2WWhVd3IySy9J
MmlINVUKLS0tIC94NnpqOG5McXkvU0NEVDZHcDExMCswU0pOTDIyY0hIWnZIaCs5
akpFWm8K6ny4xFB41oG/h8JToFnfgHBB3zWoPsLtuTCKpQE6EV+n9C/sWdB5yNJK
FoR5NdSUfxhIMK2W6HK4QAVB3oxtqqeQCY2vg3MNJ1iMkBE=
-----END AGE ENCRYPTED FILE-----
+7
View File
@@ -0,0 +1,7 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNjcnlwdCAyanV2aU1wVWx3Q0J3ZVhu
ZGdQalNBIDE4Cm9LQzlZNk80M1VhcXNVREs0S0ZqdkpkclE2ZXhDNURSaG81aEV2
Zk0zdkkKLS0tIGtOdHAwZDhYVWQ3N3Z2cmVOUktDU3NnV0ozNldSTGxrNngwMWd5
aGZET0kKSHjNMXCJvE3aYWVH5CuJ6KTBVYrtKd8EP+lua36ECKK5ARb/zKnsqd8q
C3817wLCoyeW54XNtH34QU63noK6DBtTHD1mzCp+ytPiNUY=
-----END AGE ENCRYPTED FILE-----
Executable
+39
View File
@@ -0,0 +1,39 @@
#!/bin/sh
set -e
FILES_IN_VAULT='./src/wifi-password.txt
./src/repository-builder/packager.rsa
./src/repository-builder/packager.rsa.pub
./src/wireguard.private.key
./src/wireguard.public.key
./src/authorized_keys'
age_encrypt() {
local input="$1"
local output="$1.tmp"
local AGE_PASSPHRASE=`cat ./.vault_password_file`
./cache/age/age --encrypt --passphrase --armor --output $output $input && rm $input && mv $output $input
}
age_decrypt() {
local input="$1"
local output="$1.tmp"
local AGE_PASSPHRASE=`cat ./.vault_password_file`
./cache/age/age --decrypt --output $output $input && rm $input && mv $output $input
}
encrypt() {
for FILE in $FILES_IN_VAULT; do
age_encrypt $FILE
done
}
decrypt() {
for FILE in $FILES_IN_VAULT; do
age_decrypt $FILE
done
}
$1