diff --git a/general/overlay/usr/sbin/common b/general/overlay/usr/sbin/common new file mode 100755 index 0000000000..937daf3622 --- /dev/null +++ b/general/overlay/usr/sbin/common @@ -0,0 +1,82 @@ +#!/bin/sh + +read_subshell_pid() { + IFS=' ' read -r subshell_pid _ < /proc/self/stat +} + +run_cmd_internal() { + local subshell_pid + read_subshell_pid + local run_cmd_prog="${0##*/}[$subshell_pid]" + local run_cmd_msg="$1" + local run_cmd_var="$2" + local run_cmd_fatal="$3" + shift 3 + + local run_cmd_output + run_cmd_output=$("$@" 2>&1) + local run_cmd_rc=$? + + if [ "$run_cmd_rc" -ne 0 ]; then + if [ -n "$run_cmd_msg" ]; then + logger -p user.err -t "$run_cmd_prog" "$run_cmd_msg" + fi + + local run_cmd_symbol + [ -z "$run_cmd_output" ] && run_cmd_symbol="." || run_cmd_symbol=":" + logger -p user.err -t "$run_cmd_prog" "Command \`$*\` finished with code $run_cmd_rc$run_cmd_symbol" + + if [ -n "$run_cmd_output" ]; then + printf '%s\n' "$run_cmd_output" | + while IFS= read -r line; do + logger -p user.err -t "$run_cmd_prog" "$line" + done + + echo "$run_cmd_output" >&2 + fi + + if [ "$run_cmd_fatal" = "false" ]; then + return "$run_cmd_rc" + fi + + exit "$run_cmd_rc" + fi + + if [ -n "$run_cmd_var" ]; then + eval "$run_cmd_var=\"\$run_cmd_output\"" + elif [ -n "$run_cmd_output" ]; then + echo "$run_cmd_output" + fi +} + +run_cmd_nonfatal() { + local run_cmd_msg="$1" + local run_cmd_var="$2" + shift 2 + run_cmd_internal "$run_cmd_msg" "$run_cmd_var" "false" "$@" +} + +run_cmd() { + local run_cmd_msg="$1" + local run_cmd_var="$2" + shift 2 + run_cmd_internal "$run_cmd_msg" "$run_cmd_var" "true" "$@" +} + +kill_pid_file() { + local signal + + if [ "${1:0:1}" = "-" ]; then + signal="$1" + shift + else + signal=-15 + fi + + [ -f "$1" ] || return 251 + local pid=$(cat "$1" 2>/dev/null) + [ -n "$pid" ] && [ -d "/proc/$pid" ] || return 252 + [ "$(cat "/proc/$pid/comm" 2>/dev/null)" = "$2" ] || return 253 + run_cmd_nonfatal "" "" kill "$signal" "$pid" && + run_cmd_nonfatal "" "" rm -f "$1" +} diff --git a/general/overlay/usr/sbin/kill_pid_file b/general/overlay/usr/sbin/kill_pid_file new file mode 100755 index 0000000000..11a783fd80 --- /dev/null +++ b/general/overlay/usr/sbin/kill_pid_file @@ -0,0 +1,4 @@ +#!/bin/sh + +. /usr/sbin/common +kill_pid_file "$@" diff --git a/general/overlay/usr/sbin/wireguard b/general/overlay/usr/sbin/wireguard index 428003b418..c8c13a4fdc 100755 --- a/general/overlay/usr/sbin/wireguard +++ b/general/overlay/usr/sbin/wireguard @@ -1,55 +1,6 @@ #!/bin/sh -run_cmd() { - local prog="${0##*/}" - local msg="$1" - local var="$2" - shift 2 - - local fatal - - if [ "$var" = "--non-fatal" ]; then - fatal="false" - var="" - else - fatal="true" - fi - - local output - output=$("$@" 2>&1) - local rc=$? - - if [ "$rc" -ne 0 ]; then - if [ -n "$msg" ]; then - logger -p user.err -t "$prog[$$]" "$msg" - fi - - local symbol - [ -z "$output" ] && symbol="." || symbol=":" - logger -p user.err -t "$prog[$$]" "Command \`$*\` finished with code $rc$symbol" - - if [ -n "$output" ]; then - printf '%s\n' "$output" | - while IFS= read -r line; do - logger -p user.err -t "$prog[$$]" "$line" - done - - echo "$output" >&2 - fi - - if [ "$fatal" = "false" ]; then - return - fi - - exit "$rc" - fi - - if [ -n "$var" ]; then - eval "$var=\"\$output\"" - elif [ -n "$output" ]; then - echo "$output" - fi -} +. /usr/sbin/common run_cmd "Failed to read wg_privkey U-Boot environment variable" WG_PRIVKEY fw_printenv -n wg_privkey run_cmd "Failed to read wg_endpoint U-Boot environment variable" WG_ENDPOINT fw_printenv -n wg_endpoint @@ -71,7 +22,7 @@ if ! echo "$HOST" | grep -qE '^\[|^((^|\.)(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[ done fi -( +{ echo "#" echo "[Interface]" echo "PrivateKey = $WG_PRIVKEY" @@ -83,13 +34,13 @@ fi [ -n "$WG_SHARKEY" ] && echo "PresharedKey = $WG_SHARKEY" echo "AllowedIPs = $WG_ALLOWED" echo "#" -) >>/tmp/wireguard.conf +} >/tmp/wireguard.conf run_cmd "Failed to apply wireguard configuration" "" wg setconf wg0 /tmp/wireguard.conf -run_cmd "" --non-fatal ip address add dev wg0 "$WG_ADDRESS" -run_cmd "" --non-fatal ip link set up dev wg0 +run_cmd_nonfatal "" "" ip address add dev wg0 "$WG_ADDRESS" +run_cmd_nonfatal "" "" ip link set up dev wg0 for i in $(echo "$WG_ALLOWED" | tr ',' ' '); do - run_cmd "" --non-fatal ip -4 route add "$i" dev wg0 + run_cmd_nonfatal "" "" ip -4 route add "$i" dev wg0 done diff --git a/general/package/vtund-openipc/files/tunnel b/general/package/vtund-openipc/files/tunnel index cae54f43dc..968e0773f2 100755 --- a/general/package/vtund-openipc/files/tunnel +++ b/general/package/vtund-openipc/files/tunnel @@ -1,53 +1,115 @@ #!/bin/sh -# -# OpenIPC.org | v.20230212 -# by Igor Zalatov, aka FlyRouter, aka ZigFisher -# Busybox applets: awk cat echo insmod ip modprobe sha1sum sleep tr tunctl udhcpc uptime -# -vtund_enable="true" vtund_server=${1:-vtun.localhost} vtund_port="5000" vtund_iface="tunnel" device_name="IPC-VTUND" working_dir="/tmp" +identity_cfg="$working_dir/vtund.conf" +udhcpc_pid="$working_dir/udhcpc-$vtund_iface.pid" +delay_start=0 +delay_step=10 +delay_max=300 -identity() { - identity_src=$(ip r | awk '/default/ {print $5}' | head -n 1) - identity_mac=$(cat /sys/class/net/"$identity_src"/address | tr 'a-z' 'A-Z') - identity_pas=$(echo "$identity_mac" | sha1sum | awk '{print $1}') - identity_tid=$(echo "$identity_mac" | tr -d ':') - identity_cfg=$working_dir/vtund.conf +. /usr/sbin/common + +log() { + logger -p $1 -t "$prog" "$2" } -interface() { - [ -L /sys/class/net/$vtund_iface ] || (modprobe tun; tunctl -t $vtund_iface) >/dev/null 2>&1 - [ -f $working_dir/udhcpc-$vtund_iface.pid ] && kill -9 "$(cat $working_dir/udhcpc-$vtund_iface.pid)" >/dev/null 2>&1 +warning() { + log daemon.warn "$1" } -config() { - ( echo "options {" - echo " port $vtund_port;" - echo " ifconfig /sbin/ifconfig;" - echo "}" - echo "$identity_tid {" - echo " password $identity_pas;" - echo " device $vtund_iface;" - echo " stat no;" - echo " persist yes;" - echo " keepalive 10:5;" - echo " timeout 10;" - echo " up {" - echo " ifconfig \"$vtund_iface hw ether $identity_mac mtu 1500 -multicast up\";" - echo " program \"udhcpc -T 1 -t 5 -R -b -O staticroutes -S -s tapip -p $working_dir/udhcpc-$vtund_iface.pid -i $vtund_iface -x hostname:$device_name-$identity_tid\";" - echo " };" - echo " down {" - echo " ifconfig \"$vtund_iface down\";" - echo " };" - echo "}" - ) >$identity_cfg +info() { + log daemon.info "$1" } -if [ "$vtund_enable" = "true" ]; then - (while true; do identity; interface; config; vtund -n -f "$identity_cfg" "$identity_tid" "$vtund_server" >/dev/null 2>&1; done) & -fi +ready() { + identity_src=$(ip r | awk '/default/ {print $5}' | head -n 1) + + [ -n "$identity_src" ] || { + warning "Unable to determine the default network interface" + return 1 + } + + identity_mac=$(cat "/sys/class/net/$identity_src/address" 2>/dev/null | tr 'a-z' 'A-Z') + + [ -n "$identity_mac" ] || { + warning "Unable to read the MAC address of the default network interface" + return 1 + } + + echo "$vtund_server" | grep -qE '^((^|\.)(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){4}$' && return 0 + + nslookup "$vtund_server" >/dev/null 2>&1 || { + warning "Unable to resolve the VTun server address" + return 1 + } +} + +{ + read_subshell_pid + prog="${0##*/}[$subshell_pid]" + restart_delay=$delay_start + + while true; do + while true; do + if ! ready; then + ready_delay=$delay_start + + while true; do + [ $ready_delay -lt $delay_max ] && ready_delay=$(( ready_delay + delay_step )) + sleep $ready_delay + ready && break + done + + info "Starting the tunnel to $vtund_server" + fi + + if [ ! -L "/sys/class/net/$vtund_iface" ]; then + run_cmd_nonfatal "" "" modprobe tun || break + run_cmd_nonfatal "" "" tunctl -t "$vtund_iface" || break + fi + + kill_pid_file -9 "$udhcpc_pid" udhcpc + + identity_pas=$(echo "$identity_mac" | sha1sum | awk '{print $1}') + identity_tid=$(echo "$identity_mac" | tr -d ':') + + { + echo "options {" + echo " port $vtund_port;" + echo " ifconfig /sbin/ifconfig;" + echo "}" + echo "$identity_tid {" + echo " password $identity_pas;" + echo " device $vtund_iface;" + echo " stat no;" + echo " persist yes;" + echo " keepalive 10:5;" + echo " timeout 10;" + echo " up {" + echo " ifconfig \"$vtund_iface hw ether $identity_mac mtu 1500 -multicast up\";" + echo " program \"udhcpc -T 1 -t 5 -R -b -O staticroutes -S -s tapip -p '$udhcpc_pid' -i $vtund_iface -x hostname:$device_name-$identity_tid\";" + echo " };" + echo " down {" + echo " program \"kill_pid_file -9 '$udhcpc_pid' udhcpc\";" + echo " ifconfig \"$vtund_iface down\";" + echo " };" + echo "}" + } >"$identity_cfg" + + # workaround for VTun bug described in https://bugzilla.redhat.com/show_bug.cgi?id=1462458#c26 + run_cmd_nonfatal "" "" ifconfig $vtund_iface hw ether $identity_mac mtu 1500 -multicast up || break + + vtund -n -f "$identity_cfg" "$identity_tid" "$vtund_server" >/dev/null 2>&1 && + restart_delay=$delay_start + + break + done + + [ $restart_delay -lt $delay_max ] && restart_delay=$(( restart_delay + delay_step )) + sleep $restart_delay + done +} &