diff --git a/bin/netvm-chrome.sh b/bin/netvm-chrome.sh index 4e1aa7c..a9916b0 100755 --- a/bin/netvm-chrome.sh +++ b/bin/netvm-chrome.sh @@ -8,10 +8,11 @@ set -euo pipefail NETVM_BIN="$(cd "$(dirname "$0")" && pwd)" . "$NETVM_BIN/netvm-names.sh" -HEADLESS=0; CDP_OVERRIDE=""; NO_CDP=0; PROFILE=""; URL="" -usage() { echo "usage: netvm-chrome.sh [--headless] [--cdp-port N|--no-cdp] [url]"; } +WAYPIPE=0; HEADLESS=0; CDP_OVERRIDE=""; NO_CDP=0; PROFILE=""; URL="" +usage() { echo "usage: netvm-chrome.sh [--waypipe] [--headless] [--cdp-port N|--no-cdp] [url]"; } while [ $# -gt 0 ]; do case "$1" in + --waypipe) WAYPIPE=1; shift;; --headless) HEADLESS=1; shift;; --cdp-port) CDP_OVERRIDE="$2"; shift 2;; --cdp-port=*) CDP_OVERRIDE="${1#*=}"; shift;; @@ -44,9 +45,14 @@ if [ "$NO_CDP" = 1 ]; then CDP=""; elif [ -n "$CDP_OVERRIDE" ]; then CDP="$CDP_O sudo -n "$NETVM_BIN/netvm-node-up.sh" "$NODE" | tail -1 -LAUNCH_ARGS=(launch "$PROFILE") -[ "$HEADLESS" = 1 ] && LAUNCH_ARGS+=(--no-sandbox --headless) +LAUNCH_ARGS=(launch "$PROFILE" --no-sandbox) +[ "$HEADLESS" = 1 ] && LAUNCH_ARGS+=(--headless) + [ -n "$CDP" ] && LAUNCH_ARGS+=(--cdp-port "$CDP") [ -n "$URL" ] && LAUNCH_ARGS+=("$URL") [ -n "$CDP" ] && echo "cdp: http://$PEER_IP:$CDP/json/list (local) | ssh -L $CDP:$PEER_IP:$CDP @ (remote)" -exec sudo -n "$NETVM_BIN/netvm-enter.sh" "$NODE" "$(id -u)" "$(id -g)" "$HOME" -- "$CHROME_BOX" "${LAUNCH_ARGS[@]}" +if [ "$WAYPIPE" = 1 ]; then + exec waypipe --compress=lz4 run -- sudo -n "$NETVM_BIN/netvm-enter.sh" "$NODE" "$(id -u)" "$(id -g)" "$HOME" -- "$CHROME_BOX" "${LAUNCH_ARGS[@]}" +else + exec sudo -n "$NETVM_BIN/netvm-enter.sh" "$NODE" "$(id -u)" "$(id -g)" "$HOME" -- "$CHROME_BOX" "${LAUNCH_ARGS[@]}" +fi diff --git a/bin/netvm-enter.sh b/bin/netvm-enter.sh index 1041e85..9e8240f 100755 --- a/bin/netvm-enter.sh +++ b/bin/netvm-enter.sh @@ -10,6 +10,15 @@ netvm_names "$1"; TUID="$2"; TGID="$3"; THOME="$4"; shift 4 [ "${1:-}" = "--" ]; shift RESOLV=/etc/netvm/resolv-warp.conf [ -f "$RESOLV" ] || echo "nameserver 1.1.1.1" > "$RESOLV" -ip netns exec "$NETNS" env \ + +EXEC_CMD=(ip netns exec "$NETNS" env \ NETVM_RESOLV="$RESOLV" NETVM_UID="$TUID" NETVM_GID="$TGID" NETVM_HOME="$THOME" \ - unshare --mount "$SCRIPT_DIR/netvm-enter-inner.sh" "$@" + unshare --mount "$SCRIPT_DIR/netvm-enter-inner.sh" "$@") + +if command -v systemd-run >/dev/null 2>&1; then + UNIT_NAME="netvm-${NODE}-$RANDOM" + exec systemd-run --scope -p MemoryMax=2G -p CPUQuota=200% --unit="$UNIT_NAME" "${EXEC_CMD[@]}" +else + exec "${EXEC_CMD[@]}" +fi + diff --git a/bin/netvm-node-up.sh b/bin/netvm-node-up.sh index 1c89bdc..bc64e1e 100755 --- a/bin/netvm-node-up.sh +++ b/bin/netvm-node-up.sh @@ -6,8 +6,15 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" . "$SCRIPT_DIR/netvm-names.sh" netvm_names "${1:?usage: netvm-node-up.sh }" CONF="/etc/netvm/${NODE}.conf" +STAGE_CONF="/tmp/netvm-stage-${NODE}.conf" +if [ ! -f "$CONF" ] && [ -f "$STAGE_CONF" ]; then + mkdir -p /etc/netvm 2>/dev/null || true + install -m 600 -o root -g root "$STAGE_CONF" "$CONF" + rm -f "$STAGE_CONF" +fi [ -f "$CONF" ] || { echo "missing $CONF (human: netvm-new-identity.sh $NODE)"; exit 1; } chmod 600 "$CONF" + # let the operator user stat (not read) identities: 711 dir, 600 files chmod 711 /etc/netvm 2>/dev/null || true nsexec() { ip netns exec "$NETNS" "$@"; } @@ -100,4 +107,25 @@ else fi EGRESS=$(nsexec curl -sk --max-time 15 'https://1.1.1.1/cdn-cgi/trace' 2>/dev/null | grep -oP '^ip=\K.*' || true) fi -echo "node=$NODE netns=$NETNS ifaces=$WG/$VETH egress=${EGRESS:-unknown}" + +if [ -z "$EGRESS" ]; then + echo "ERROR: Egress check failed for node '$NODE' (warp interface down or unroutable). Aborting." >&2 + EMAIL_ALERT="/home/super/Projects/email-alert/email-alert" + if [ -x "$EMAIL_ALERT" ]; then + "$EMAIL_ALERT" send --priority high --subject "NetVM Alert: Node '$NODE' Egress Failed" "WireGuard WARP tunnel for node '$NODE' failed egress verification. Execution aborted to protect IP isolation." || true + fi + exit 1 +fi + +REAL_USER="${SUDO_USER:-$USER}" +REAL_HOME=$(eval echo "~$REAL_USER") +AUDIT_DIR="$REAL_HOME/.local/share/chrome-box" +mkdir -p "$AUDIT_DIR" 2>/dev/null || true +chown "$REAL_USER:" "$AUDIT_DIR" 2>/dev/null || true +TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ") +python3 -c "import json; print(json.dumps({'timestamp': '$TIMESTAMP', 'event': 'node_up', 'node': '$NODE', 'netns': '$NETNS', 'veth_ip': '$PEER_IP', 'cdp_port': $CDP_PORT, 'egress_ip': '$EGRESS', 'user': '$REAL_USER'}))" >> "$AUDIT_DIR/audit.jsonl" 2>/dev/null || true +chown "$REAL_USER:" "$AUDIT_DIR/audit.jsonl" 2>/dev/null || true + +echo "node=$NODE netns=$NETNS ifaces=$WG/$VETH egress=$EGRESS" + +