mirror of
https://gitlab.com/hacklab01/pivilion.git
synced 2026-08-07 00:18:23 +00:00
Add modern Raspberry Pi OS compatibility
This commit is contained in:
parent
4636a4f4f6
commit
3b7a16564b
35 changed files with 725 additions and 15678 deletions
113
usr/local/lib/pivilion/common.sh
Normal file
113
usr/local/lib/pivilion/common.sh
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Shared configuration and small helpers for the Pivilion commands.
|
||||
|
||||
PIVILION_CONFIG=""
|
||||
|
||||
_pivilion_trim() {
|
||||
local value=$1
|
||||
value="${value#"${value%%[![:space:]]*}"}"
|
||||
value="${value%"${value##*[![:space:]]}"}"
|
||||
printf '%s' "$value"
|
||||
}
|
||||
|
||||
_pivilion_config_value() {
|
||||
local key=$1 file line name value
|
||||
for file in /boot/firmware/pivilion.conf /boot/pivilion.conf /etc/pivilion.conf /etc/pivilion.defaults; do
|
||||
[ -r "$file" ] || continue
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
line=$(_pivilion_trim "$line")
|
||||
case "$line" in ''|'#'*) continue ;; esac
|
||||
name=$(_pivilion_trim "${line%%=*}")
|
||||
[ "$name" = "$key" ] || continue
|
||||
value=$(_pivilion_trim "${line#*=}")
|
||||
case "$value" in
|
||||
\"*\") value=${value#\"}; value=${value%\"} ;;
|
||||
\'*\') value=${value#\'}; value=${value%\'} ;;
|
||||
esac
|
||||
printf '%s' "$value"
|
||||
return 0
|
||||
done < "$file"
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
pivilion_load_config() {
|
||||
local default_user configured ssid_bytes
|
||||
default_user=${SUDO_USER:-${USER:-}}
|
||||
[ -n "$default_user" ] && [ "$default_user" != root ] || default_user=$(id -nu 1000 2>/dev/null || true)
|
||||
|
||||
configured=$(_pivilion_config_value PIVILION_USER || true)
|
||||
PIVILION_USER=${configured:-$default_user}
|
||||
[ -n "$PIVILION_USER" ] || { echo "Cannot determine PIVILION_USER" >&2; return 1; }
|
||||
getent passwd "$PIVILION_USER" >/dev/null || { echo "Configured user '$PIVILION_USER' does not exist" >&2; return 1; }
|
||||
PIVILION_GROUP=$(id -gn "$PIVILION_USER")
|
||||
|
||||
configured=$(_pivilion_config_value PIVILION_HOME || true)
|
||||
PIVILION_HOME=${configured:-$(getent passwd "$PIVILION_USER" | cut -d: -f6)}
|
||||
configured=$(_pivilion_config_value PIVILION_DIR || true)
|
||||
PIVILION_DIR=${configured:-$PIVILION_HOME/pivilion}
|
||||
configured=$(_pivilion_config_value PIVILION_WEBROOT || true)
|
||||
PIVILION_WEBROOT=${configured:-/var/www/html/pivilion}
|
||||
configured=$(_pivilion_config_value PIVILION_MODE || true)
|
||||
PIVILION_MODE=${configured:-onion}
|
||||
configured=$(_pivilion_config_value PIVILION_HOTSPOT_SSID || true)
|
||||
PIVILION_HOTSPOT_SSID=${configured:-pivilion}
|
||||
configured=$(_pivilion_config_value PIVILION_WIFI_INTERFACE || true)
|
||||
PIVILION_WIFI_INTERFACE=${configured:-}
|
||||
|
||||
case "$PIVILION_MODE" in onion|hotspot) ;; *) echo "PIVILION_MODE must be onion or hotspot" >&2; return 1 ;; esac
|
||||
ssid_bytes=$(LC_ALL=C printf '%s' "$PIVILION_HOTSPOT_SSID" | wc -c)
|
||||
[ "$ssid_bytes" -ge 1 ] && [ "$ssid_bytes" -le 32 ] || {
|
||||
echo "PIVILION_HOTSPOT_SSID must contain 1-32 bytes" >&2; return 1;
|
||||
}
|
||||
case "$PIVILION_HOME$PIVILION_DIR$PIVILION_WEBROOT$PIVILION_WIFI_INTERFACE$PIVILION_HOTSPOT_SSID" in
|
||||
*$'\n'*|*$'\r'*) echo "Invalid control character in Pivilion configuration" >&2; return 1 ;;
|
||||
esac
|
||||
case "$PIVILION_HOME:$PIVILION_DIR:$PIVILION_WEBROOT" in
|
||||
/*:/*:/*) ;; *) echo "Pivilion paths must be absolute" >&2; return 1 ;;
|
||||
esac
|
||||
[[ "$PIVILION_HOME" =~ ^/[A-Za-z0-9._/+:-]+$ && "$PIVILION_DIR" =~ ^/[A-Za-z0-9._/+:-]+$ && "$PIVILION_WEBROOT" =~ ^/[A-Za-z0-9._/+:-]+$ ]] || {
|
||||
echo "Pivilion paths contain unsupported characters" >&2; return 1;
|
||||
}
|
||||
[ -z "$PIVILION_WIFI_INTERFACE" ] || [[ "$PIVILION_WIFI_INTERFACE" =~ ^[A-Za-z0-9._:-]+$ ]] || {
|
||||
echo "Invalid PIVILION_WIFI_INTERFACE" >&2; return 1;
|
||||
}
|
||||
export PIVILION_USER PIVILION_GROUP PIVILION_HOME PIVILION_DIR PIVILION_WEBROOT PIVILION_MODE PIVILION_HOTSPOT_SSID PIVILION_WIFI_INTERFACE
|
||||
}
|
||||
|
||||
pivilion_wifi_interface() {
|
||||
local iface
|
||||
if [ -n "${PIVILION_WIFI_INTERFACE:-}" ]; then printf '%s\n' "$PIVILION_WIFI_INTERFACE"; return; fi
|
||||
if command -v nmcli >/dev/null 2>&1; then
|
||||
iface=$(nmcli -t -f DEVICE,TYPE device status 2>/dev/null | awk -F: '$2=="wifi" {print $1; exit}')
|
||||
[ -n "$iface" ] && { printf '%s\n' "$iface"; return; }
|
||||
fi
|
||||
if command -v iw >/dev/null 2>&1; then
|
||||
iface=$(iw dev 2>/dev/null | awk '$1=="Interface" {print $2; exit}')
|
||||
[ -n "$iface" ] && { printf '%s\n' "$iface"; return; }
|
||||
fi
|
||||
iface=$(find /sys/class/net -maxdepth 1 -type l -name 'wl*' -printf '%f\n' 2>/dev/null | head -n1)
|
||||
[ -n "$iface" ] && printf '%s\n' "$iface"
|
||||
}
|
||||
|
||||
pivilion_uses_networkmanager() {
|
||||
command -v nmcli >/dev/null 2>&1 && systemctl is-active --quiet NetworkManager
|
||||
}
|
||||
|
||||
pivilion_set_mode() {
|
||||
local mode=$1
|
||||
case "$mode" in onion|hotspot) ;; *) return 2 ;; esac
|
||||
install -d -m 0755 -o "$PIVILION_USER" -g "$PIVILION_GROUP" "$PIVILION_DIR"
|
||||
printf '%s\n' "$mode" | install -m 0644 -o "$PIVILION_USER" -g "$PIVILION_GROUP" /dev/stdin "$PIVILION_DIR/mode"
|
||||
}
|
||||
|
||||
pivilion_current_mode() {
|
||||
local mode
|
||||
mode=$(head -n1 "$PIVILION_DIR/mode" 2>/dev/null || true)
|
||||
case "$mode" in onion|hotspot) printf '%s\n' "$mode" ;; *) printf '%s\n' "$PIVILION_MODE" ;; esac
|
||||
}
|
||||
|
||||
pivilion_require_root() {
|
||||
[ "$(id -u)" -eq 0 ] || { echo "This operation must run as root (use sudo)." >&2; return 1; }
|
||||
}
|
||||
138
usr/local/lib/pivilion/mode.sh
Executable file
138
usr/local/lib/pivilion/mode.sh
Executable file
|
|
@ -0,0 +1,138 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
source /usr/local/lib/pivilion/common.sh
|
||||
pivilion_require_root
|
||||
pivilion_load_config
|
||||
|
||||
MODE=${1:-$(pivilion_current_mode)}
|
||||
IFACE=$(pivilion_wifi_interface)
|
||||
[ -n "$IFACE" ] || { echo "No Wi-Fi interface found; set PIVILION_WIFI_INTERFACE" >&2; exit 1; }
|
||||
RUN_DIR=/run/pivilion
|
||||
DNSMASQ_CONF=/etc/dnsmasq.d/pivilion-runtime.conf
|
||||
NM_HOTSPOT=pivilion-hotspot
|
||||
|
||||
stop_hotspot() {
|
||||
systemctl stop pivilion-dnsmasq.service 2>/dev/null || true
|
||||
rm -f "$DNSMASQ_CONF"
|
||||
nft delete table inet pivilion 2>/dev/null || true
|
||||
if pivilion_uses_networkmanager; then
|
||||
nmcli connection down "$NM_HOTSPOT" 2>/dev/null || true
|
||||
nmcli connection delete "$NM_HOTSPOT" 2>/dev/null || true
|
||||
else
|
||||
systemctl stop hostapd 2>/dev/null || true
|
||||
ip address flush dev "$IFACE" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
write_dnsmasq_config() {
|
||||
install -d -m 0755 /etc/dnsmasq.d
|
||||
cat > "$DNSMASQ_CONF" <<EOF
|
||||
interface=$IFACE
|
||||
bind-dynamic
|
||||
listen-address=10.1.1.1
|
||||
dhcp-range=10.1.1.2,10.1.1.254,255.255.255.0,72h
|
||||
dhcp-option=option:router,10.1.1.1
|
||||
dhcp-authoritative
|
||||
address=/#/10.1.1.1
|
||||
EOF
|
||||
}
|
||||
|
||||
start_firewall() {
|
||||
install -d -m 0755 "$RUN_DIR"
|
||||
cat > "$RUN_DIR/pivilion.nft" <<EOF
|
||||
table inet pivilion {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority dstnat; policy accept;
|
||||
iifname "$IFACE" udp dport 53 redirect to :53
|
||||
iifname "$IFACE" tcp dport 53 redirect to :53
|
||||
iifname "$IFACE" tcp dport 80 redirect to :80
|
||||
}
|
||||
}
|
||||
EOF
|
||||
nft delete table inet pivilion 2>/dev/null || true
|
||||
nft -f "$RUN_DIR/pivilion.nft"
|
||||
}
|
||||
|
||||
start_hotspot() {
|
||||
stop_hotspot
|
||||
rfkill unblock wifi 2>/dev/null || true
|
||||
systemctl start apache2
|
||||
if pivilion_uses_networkmanager; then
|
||||
nmcli connection add type wifi ifname "$IFACE" con-name "$NM_HOTSPOT" ssid "$PIVILION_HOTSPOT_SSID"
|
||||
nmcli connection modify "$NM_HOTSPOT" 802-11-wireless.mode ap 802-11-wireless.band bg \
|
||||
ipv4.method manual ipv4.addresses 10.1.1.1/24 ipv4.never-default yes ipv6.method disabled
|
||||
nmcli connection up "$NM_HOTSPOT"
|
||||
else
|
||||
systemctl stop "wpa_supplicant@$IFACE.service" 2>/dev/null || true
|
||||
command -v dhcpcd >/dev/null 2>&1 && dhcpcd -k "$IFACE" 2>/dev/null || true
|
||||
ip link set "$IFACE" down
|
||||
ip address flush dev "$IFACE"
|
||||
ip address add 10.1.1.1/24 dev "$IFACE"
|
||||
ip link set "$IFACE" up
|
||||
install -d -m 0755 /etc/hostapd
|
||||
cat > /etc/hostapd/hostapd.conf <<EOF
|
||||
interface=$IFACE
|
||||
driver=nl80211
|
||||
ssid=$PIVILION_HOTSPOT_SSID
|
||||
hw_mode=g
|
||||
channel=6
|
||||
auth_algs=1
|
||||
wmm_enabled=0
|
||||
EOF
|
||||
systemctl unmask hostapd 2>/dev/null || true
|
||||
systemctl restart hostapd
|
||||
fi
|
||||
write_dnsmasq_config
|
||||
dnsmasq --test --conf-file="$DNSMASQ_CONF"
|
||||
systemctl restart pivilion-dnsmasq.service
|
||||
start_firewall
|
||||
echo "Pivilion hotspot '$PIVILION_HOTSPOT_SSID' is active on $IFACE (10.1.1.1)."
|
||||
}
|
||||
|
||||
update_torname() {
|
||||
local source=/var/lib/tor/pivilion/hostname hostname tmp i
|
||||
for i in $(seq 1 30); do
|
||||
if [ -s "$source" ]; then
|
||||
hostname=$(tr -d '\r\n' < "$source")
|
||||
if [[ ! "$hostname" =~ ^[a-z2-7]{56}\.onion$ ]]; then
|
||||
echo "Tor produced an invalid v3 onion hostname." >&2
|
||||
return 1
|
||||
fi
|
||||
tmp=$(mktemp "$PIVILION_DIR/.torname.XXXXXX")
|
||||
printf '%s\n' "$hostname" > "$tmp"
|
||||
chown "$PIVILION_USER:$PIVILION_GROUP" "$tmp"
|
||||
chmod 0644 "$tmp"
|
||||
mv -f "$tmp" "$PIVILION_DIR/torname"
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
echo "Tor started, but no onion hostname was generated within 30 seconds." >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
start_onion() {
|
||||
stop_hotspot
|
||||
if pivilion_uses_networkmanager; then
|
||||
nmcli connection up pivilion-onion 2>/dev/null || echo "No saved Pivilion Wi-Fi connection; run pikey." >&2
|
||||
else
|
||||
systemctl restart dhcpcd 2>/dev/null || true
|
||||
systemctl restart "wpa_supplicant@$IFACE.service" 2>/dev/null || systemctl restart wpa_supplicant 2>/dev/null || true
|
||||
fi
|
||||
rm -f "$PIVILION_WEBROOT/gen/.htaccess"
|
||||
systemctl start apache2
|
||||
if systemctl cat tor@default.service >/dev/null 2>&1; then
|
||||
systemctl restart tor@default.service
|
||||
else
|
||||
systemctl restart tor.service
|
||||
fi
|
||||
update_torname || true
|
||||
echo "Pivilion onion mode is active."
|
||||
}
|
||||
|
||||
case "$MODE" in
|
||||
hotspot) start_hotspot ;;
|
||||
onion) start_onion ;;
|
||||
*) echo "Unknown Pivilion mode: $MODE" >&2; exit 2 ;;
|
||||
esac
|
||||
Loading…
Add table
Add a link
Reference in a new issue