fix: make Guacamole fixture dual-stack and keep VM display awake
This commit is contained in:
@@ -893,6 +893,14 @@ watchdog/tunnel is bound
|
|||||||
only to the helper's private Docker gateway. Stop the helper before the normal
|
only to the helper's private Docker gateway. Stop the helper before the normal
|
||||||
`test-host reset`. It is a recovery interface, not a product component or a
|
`test-host reset`. It is a recovery interface, not a product component or a
|
||||||
replacement for Guest Control/native test automation.
|
replacement for Guest Control/native test automation.
|
||||||
|
Because Windows can power off the virtual monitor while the VM remains
|
||||||
|
running, `test-host prepare` must also reapply the disposable display/sleep
|
||||||
|
keepalive and record `prepare-display-keepalive`. A zero-bpp VRDE framebuffer
|
||||||
|
otherwise leaves an otherwise authenticated Guacamole browser at “Waiting for
|
||||||
|
response”. If the public browser hostname has an AAAA record, `rdp-access up
|
||||||
|
--bind 0.0.0.0` must own a tracked IPv6-to-IPv4 forward and expose its
|
||||||
|
`ipv6_forward` status; this prevents a browser selecting IPv6 for the WebSocket
|
||||||
|
from silently taking a different, refused path.
|
||||||
|
|
||||||
For this provisioned lane, the approved host-only credential-file location is
|
For this provisioned lane, the approved host-only credential-file location is
|
||||||
`/home/cabbage/.local/share/rvbox-secrets/rvbox-win10-test.password`. It must
|
`/home/cabbage/.local/share/rvbox-secrets/rvbox-win10-test.password`. It must
|
||||||
|
|||||||
+10
-3
@@ -91,6 +91,9 @@ self-signed HTTPS Guacamole gateway while retaining VRDE on Helium loopback and
|
|||||||
the reconnecting SSH watchdog/tunnel on a private Docker gateway. Follow its
|
the reconnecting SSH watchdog/tunnel on a private Docker gateway. Follow its
|
||||||
full lease/prepare/up/
|
full lease/prepare/up/
|
||||||
down/reset lifecycle; it is not an alternative to the native test controller.
|
down/reset lifecycle; it is not an alternative to the native test controller.
|
||||||
|
In public-bind mode the helper also owns a tracked IPv6-to-IPv4 `socat` forward
|
||||||
|
when the browser hostname has an AAAA record; check `ipv6_forward=active` in
|
||||||
|
`rdp-access status` before diagnosing a browser-side “Waiting for response”.
|
||||||
|
|
||||||
## Snapshots and reset contract
|
## Snapshots and reset contract
|
||||||
|
|
||||||
@@ -112,10 +115,14 @@ stateful run must:
|
|||||||
1. Acquire the run lease and verify the VM name, UUID, and snapshot UUID.
|
1. Acquire the run lease and verify the VM name, UUID, and snapshot UUID.
|
||||||
2. Restore `baseline-clean-administrator` if the current state is not the baseline.
|
2. Restore `baseline-clean-administrator` if the current state is not the baseline.
|
||||||
3. Start headless and wait for `VMState=running` plus Guest Additions readiness.
|
3. Start headless and wait for `VMState=running` plus Guest Additions readiness.
|
||||||
4. Run the bounded test, collect redacted artifacts, and close every Guest
|
4. Apply the disposable display/sleep keepalive (`monitor-timeout`, standby,
|
||||||
|
and hibernate timers set to zero) so VirtualBox VRDE cannot expose a
|
||||||
|
zero-bpp framebuffer after Windows idle timeout. This is recorded as
|
||||||
|
`prepare-display-keepalive` and is reapplied after every snapshot restore.
|
||||||
|
5. Run the bounded test, collect redacted artifacts, and close every Guest
|
||||||
Control process that was opened by the run.
|
Control process that was opened by the run.
|
||||||
5. Request a graceful guest shutdown and wait for `VMState=poweroff`.
|
6. Request a graceful guest shutdown and wait for `VMState=poweroff`.
|
||||||
6. Restore `baseline-clean-administrator` again and leave the VM powered off.
|
7. Restore `baseline-clean-administrator` again and leave the VM powered off.
|
||||||
|
|
||||||
Use `controlvm ... poweroff` only for a hung, disposable test; it can lose
|
Use `controlvm ... poweroff` only for a hung, disposable test; it can lose
|
||||||
guest state. Never delete any clean snapshot, unregister the VM, or alter
|
guest state. Never delete any clean snapshot, unregister the VM, or alter
|
||||||
|
|||||||
@@ -208,6 +208,9 @@ Interactive browser access is a deliberately temporary recovery path only. See
|
|||||||
[`test/rdp-access`](../test/rdp-access/README.md) for the Docker-only,
|
[`test/rdp-access`](../test/rdp-access/README.md) for the Docker-only,
|
||||||
self-signed HTTPS Guacamole lifecycle; it must be started only after the native
|
self-signed HTTPS Guacamole lifecycle; it must be started only after the native
|
||||||
fixture controller has prepared and leased the VM, and stopped before reset.
|
fixture controller has prepared and leased the VM, and stopped before reset.
|
||||||
|
For a public hostname with an AAAA record, its `up --bind 0.0.0.0` mode also
|
||||||
|
tracks an IPv6-to-IPv4 forward; verify `ipv6_forward=active` before debugging
|
||||||
|
a browser stuck at “Waiting for response”.
|
||||||
|
|
||||||
The Linux production Compose asset has a separate, loopback-only smoke lane. It
|
The Linux production Compose asset has a separate, loopback-only smoke lane. It
|
||||||
uses a disposable self-signed key only under the ignored `.test-runs` tree,
|
uses a disposable self-signed key only under the ignored `.test-runs` tree,
|
||||||
|
|||||||
@@ -316,6 +316,18 @@ wait_guest_additions() {
|
|||||||
fail "Guest Additions did not publish version and Windows OS-release properties"
|
fail "Guest Additions did not publish version and Windows OS-release properties"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configure_display_keepalive() {
|
||||||
|
# VirtualBox VRDE reports a zero-bpp framebuffer when Windows powers off
|
||||||
|
# the virtual monitor. That leaves an authenticated Guacamole tunnel in
|
||||||
|
# its "Waiting for response" state even though RDP negotiation succeeded.
|
||||||
|
# Keep the disposable diagnostic fixture awake; this is deliberately
|
||||||
|
# applied after every snapshot restore because power-plan state belongs to
|
||||||
|
# the guest snapshot, not to the controller.
|
||||||
|
provisioner_run --exe 'C:\Windows\System32\cmd.exe' --wait-stdout --wait-stderr --unquoted-args -- \
|
||||||
|
/d /s /c '(powercfg /change monitor-timeout-ac 0 && powercfg /change monitor-timeout-dc 0 && powercfg /change standby-timeout-ac 0 && powercfg /change standby-timeout-dc 0 && powercfg /change hibernate-timeout-ac 0 && powercfg /change hibernate-timeout-dc 0 && echo RVBOX_GUEST_OK)' >/dev/null || \
|
||||||
|
fail "fixture provisioner could not disable disposable display/sleep timers"
|
||||||
|
}
|
||||||
|
|
||||||
wait_service() {
|
wait_service() {
|
||||||
wanted=$1
|
wanted=$1
|
||||||
attempt=0
|
attempt=0
|
||||||
@@ -366,6 +378,8 @@ case "$action" in
|
|||||||
step prepare-vm-started
|
step prepare-vm-started
|
||||||
wait_guest_additions
|
wait_guest_additions
|
||||||
step prepare-guest-additions-ready
|
step prepare-guest-additions-ready
|
||||||
|
configure_display_keepalive
|
||||||
|
step prepare-display-keepalive
|
||||||
assert_clean_guest
|
assert_clean_guest
|
||||||
step prepare-clean-baseline-verified
|
step prepare-clean-baseline-verified
|
||||||
;;
|
;;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ The helper builds this private path:
|
|||||||
|
|
||||||
```text
|
```text
|
||||||
browser -- HTTPS/self-signed --> nginx + Guacamole containers
|
browser -- HTTPS/self-signed --> nginx + Guacamole containers
|
||||||
|
(IPv4 and, in public mode, a tracked IPv6 forward)
|
||||||
|
|
|
|
||||||
private Docker gateway
|
private Docker gateway
|
||||||
|
|
|
|
||||||
@@ -69,9 +70,23 @@ port (`54001`). They can be overridden without editing tracked files through
|
|||||||
`RVBOX_TEST_VBOX_HOST`, `RDP_ACCESS_VRDE_HOST`, `RDP_ACCESS_VRDE_PORT`,
|
`RVBOX_TEST_VBOX_HOST`, `RDP_ACCESS_VRDE_HOST`, `RDP_ACCESS_VRDE_PORT`,
|
||||||
`RDP_ACCESS_WEB_USER`, `RDP_ACCESS_RDP_USER`, `RDP_ACCESS_BIND`,
|
`RDP_ACCESS_WEB_USER`, `RDP_ACCESS_RDP_USER`, `RDP_ACCESS_BIND`,
|
||||||
`RDP_ACCESS_HTTP_PORT`, `RDP_ACCESS_TUNNEL_PORT`, and
|
`RDP_ACCESS_HTTP_PORT`, `RDP_ACCESS_TUNNEL_PORT`, and
|
||||||
`RDP_ACCESS_PUBLIC_HOST`. The helper deliberately limits the VRDE host to
|
`RDP_ACCESS_PUBLIC_HOST`, `RDP_ACCESS_IPV6_BIND`, and
|
||||||
|
`RDP_ACCESS_IPV6_FORWARD`. The helper deliberately limits the VRDE host to
|
||||||
Helium loopback (`127.0.0.1` or `localhost`) so an override cannot accidentally
|
Helium loopback (`127.0.0.1` or `localhost`) so an override cannot accidentally
|
||||||
turn the diagnostic server into a remote target.
|
turn the diagnostic server into a remote target.
|
||||||
|
Set `RDP_ACCESS_GUACD_LOG_LEVEL=debug` temporarily when collecting detailed
|
||||||
|
guacd/RDP negotiation diagnostics; the default is `info`.
|
||||||
|
|
||||||
|
When `--bind 0.0.0.0` is used, `up` also starts a tracked `socat` listener on
|
||||||
|
`[::]:$RDP_ACCESS_HTTP_PORT` and forwards it to the IPv4 gateway listener. This
|
||||||
|
matters when the public hostname has an AAAA record: some browsers choose IPv6
|
||||||
|
for the WebSocket even if the initial page used IPv4. The listener is recorded
|
||||||
|
under `.runtime/ipv6-forward.pid` and is removed by `down` and `clean`. Its
|
||||||
|
default bind is `::` (`RDP_ACCESS_IPV6_BIND`); set
|
||||||
|
`RDP_ACCESS_IPV6_FORWARD=never` to deliberately use IPv4 only, `always` to make
|
||||||
|
IPv6 startup a hard requirement, or leave the default `auto` for a warning and
|
||||||
|
an IPv4-only fallback when `socat` is unavailable. `status` reports
|
||||||
|
`ipv6_forward=active`, `active_external`, `inactive`, or `disabled`.
|
||||||
|
|
||||||
If `up` is run again while the Compose services are still running, it is
|
If `up` is run again while the Compose services are still running, it is
|
||||||
idempotent: an existing healthy tunnel is reused, and a missing tunnel is
|
idempotent: an existing healthy tunnel is reused, and a missing tunnel is
|
||||||
@@ -123,7 +138,9 @@ test/rdp-access/rdp-access url
|
|||||||
|
|
||||||
If the browser reaches Guacamole but stays on “Waiting for response”, run
|
If the browser reaches Guacamole but stays on “Waiting for response”, run
|
||||||
`status` first. Confirm `private_tunnel=active` (or
|
`status` first. Confirm `private_tunnel=active` (or
|
||||||
`active_external`), then check the VM state and the last lines of
|
`active_external`) and, for a public dual-stack hostname,
|
||||||
|
`ipv6_forward=active` (or a known-good external forward). Then check the VM
|
||||||
|
state and the last lines of
|
||||||
`.runtime/tunnel.log`. A tunnel can be recreated without losing the Compose
|
`.runtime/tunnel.log`. A tunnel can be recreated without losing the Compose
|
||||||
stack by running `up` again. This helper already uses `security=rdp` and
|
stack by running `up` again. This helper already uses `security=rdp` and
|
||||||
disables Guacamole's GFX extension, which are required by the fixture's legacy
|
disables Guacamole's GFX extension, which are required by the fixture's legacy
|
||||||
@@ -132,9 +149,11 @@ VRDE server. Do not switch the helper to native Windows RDP:
|
|||||||
unusable, stop this helper and use Guest Control for the deterministic portion
|
unusable, stop this helper and use Guest Control for the deterministic portion
|
||||||
of the work; record the blocked interactive step in the native test report.
|
of the work; record the blocked interactive step in the native test report.
|
||||||
|
|
||||||
The helper requires Docker/Docker Compose, SSH access through the existing
|
The helper requires Docker/Docker Compose, `socat` for the optional public
|
||||||
`helium-remote` alias, and the fixture password file documented in
|
dual-stack forward, SSH access through the existing `helium-remote` alias, and
|
||||||
|
the fixture password file documented in
|
||||||
[`docs/testing-vm.md`](../../docs/testing-vm.md). It does not install host
|
[`docs/testing-vm.md`](../../docs/testing-vm.md). It does not install host
|
||||||
packages, write credentials into Git, or alter VM settings. The tracked files
|
packages, write credentials into Git, or alter VM identity/settings. The
|
||||||
are Docker-only configuration and the controller script; all generated content
|
authoritative `test-host prepare` step applies only the disposable
|
||||||
is ignored beneath `.runtime/`.
|
display/sleep keepalive needed by VirtualBox VRDE; all generated content is
|
||||||
|
ignored beneath `.runtime/`.
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
services:
|
services:
|
||||||
guacd:
|
guacd:
|
||||||
image: guacamole/guacd:1.6.0
|
image: guacamole/guacd:1.6.0
|
||||||
|
environment:
|
||||||
|
LOG_LEVEL: ${RDP_ACCESS_GUACD_LOG_LEVEL:-info}
|
||||||
|
|
||||||
guacamole:
|
guacamole:
|
||||||
image: guacamole/guacamole:1.6.0
|
image: guacamole/guacamole:1.6.0
|
||||||
|
|||||||
@@ -15,5 +15,8 @@ server {
|
|||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "upgrade";
|
||||||
proxy_buffering off;
|
proxy_buffering off;
|
||||||
|
proxy_read_timeout 1h;
|
||||||
|
proxy_send_timeout 1h;
|
||||||
|
proxy_set_header X-Accel-Buffering no;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+113
-1
@@ -16,6 +16,9 @@ project=rvbox-rdp-access
|
|||||||
: "${RDP_ACCESS_PUBLIC_HOST:=localhost}"
|
: "${RDP_ACCESS_PUBLIC_HOST:=localhost}"
|
||||||
: "${RDP_ACCESS_WEB_USER:=rvboxtest}"
|
: "${RDP_ACCESS_WEB_USER:=rvboxtest}"
|
||||||
: "${RDP_ACCESS_RDP_USER:=rvboxtest}"
|
: "${RDP_ACCESS_RDP_USER:=rvboxtest}"
|
||||||
|
: "${RDP_ACCESS_GUACD_LOG_LEVEL:=info}"
|
||||||
|
: "${RDP_ACCESS_IPV6_BIND:=::}"
|
||||||
|
: "${RDP_ACCESS_IPV6_FORWARD:=auto}"
|
||||||
: "${RVBOX_TEST_VBOX_HOST:=helium-remote}"
|
: "${RVBOX_TEST_VBOX_HOST:=helium-remote}"
|
||||||
: "${RDP_ACCESS_VRDE_HOST:=127.0.0.1}"
|
: "${RDP_ACCESS_VRDE_HOST:=127.0.0.1}"
|
||||||
: "${RDP_ACCESS_VRDE_PORT:=3389}"
|
: "${RDP_ACCESS_VRDE_PORT:=3389}"
|
||||||
@@ -46,7 +49,10 @@ up options:
|
|||||||
Environment equivalents: RDP_ACCESS_BIND, RDP_ACCESS_HTTP_PORT,
|
Environment equivalents: RDP_ACCESS_BIND, RDP_ACCESS_HTTP_PORT,
|
||||||
RDP_ACCESS_TUNNEL_PORT, RDP_ACCESS_PUBLIC_HOST, RDP_ACCESS_WEB_USER,
|
RDP_ACCESS_TUNNEL_PORT, RDP_ACCESS_PUBLIC_HOST, RDP_ACCESS_WEB_USER,
|
||||||
RDP_ACCESS_RDP_USER, RVBOX_TEST_VBOX_HOST, RDP_ACCESS_VRDE_HOST, and
|
RDP_ACCESS_RDP_USER, RVBOX_TEST_VBOX_HOST, RDP_ACCESS_VRDE_HOST, and
|
||||||
RDP_ACCESS_VRDE_PORT.
|
RDP_ACCESS_VRDE_PORT. In public mode, RDP_ACCESS_IPV6_BIND and
|
||||||
|
RDP_ACCESS_IPV6_FORWARD (auto, always, or never) control the reversible
|
||||||
|
IPv6-to-IPv4 listener for dual-stack hostnames. Set
|
||||||
|
RDP_ACCESS_GUACD_LOG_LEVEL=debug for temporary protocol diagnostics.
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,6 +75,7 @@ compose() {
|
|||||||
RDP_ACCESS_RUNTIME_DIR=$runtime_dir \
|
RDP_ACCESS_RUNTIME_DIR=$runtime_dir \
|
||||||
RDP_ACCESS_BIND=$RDP_ACCESS_BIND \
|
RDP_ACCESS_BIND=$RDP_ACCESS_BIND \
|
||||||
RDP_ACCESS_HTTP_PORT=$RDP_ACCESS_HTTP_PORT \
|
RDP_ACCESS_HTTP_PORT=$RDP_ACCESS_HTTP_PORT \
|
||||||
|
RDP_ACCESS_GUACD_LOG_LEVEL=$RDP_ACCESS_GUACD_LOG_LEVEL \
|
||||||
RDP_ACCESS_CERT_NAME=$RDP_ACCESS_PUBLIC_HOST \
|
RDP_ACCESS_CERT_NAME=$RDP_ACCESS_PUBLIC_HOST \
|
||||||
RDP_ACCESS_CERT_SAN=$cert_san \
|
RDP_ACCESS_CERT_SAN=$cert_san \
|
||||||
RDP_ACCESS_HOST_UID=$(id -u) \
|
RDP_ACCESS_HOST_UID=$(id -u) \
|
||||||
@@ -100,6 +107,8 @@ cert_name_file=$runtime_dir/cert-name
|
|||||||
tunnel_stop_file=$runtime_dir/tunnel.stop
|
tunnel_stop_file=$runtime_dir/tunnel.stop
|
||||||
tunnel_pid_file=$runtime_dir/tunnel-watchdog.pid
|
tunnel_pid_file=$runtime_dir/tunnel-watchdog.pid
|
||||||
tunnel_log_file=$runtime_dir/tunnel.log
|
tunnel_log_file=$runtime_dir/tunnel.log
|
||||||
|
ipv6_pid_file=$runtime_dir/ipv6-forward.pid
|
||||||
|
ipv6_log_file=$runtime_dir/ipv6-forward.log
|
||||||
|
|
||||||
stop_tunnel() {
|
stop_tunnel() {
|
||||||
mkdir -p "$runtime_dir"
|
mkdir -p "$runtime_dir"
|
||||||
@@ -135,6 +144,102 @@ stop_tunnel() {
|
|||||||
rm -f "$tunnel_pid_file" "$tunnel_stop_file"
|
rm -f "$tunnel_pid_file" "$tunnel_stop_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ipv6_process_matches() {
|
||||||
|
ipv6_pid=$1
|
||||||
|
ipv6_cmd=$(ps -p "$ipv6_pid" -o args= 2>/dev/null || true)
|
||||||
|
case $ipv6_cmd in
|
||||||
|
*"TCP6-LISTEN:$RDP_ACCESS_HTTP_PORT"*"TCP4:127.0.0.1:$RDP_ACCESS_HTTP_PORT"*) return 0 ;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
ipv6_listener_active() {
|
||||||
|
command -v ss >/dev/null 2>&1 || return 1
|
||||||
|
ss -H -ltn6 2>/dev/null | awk -v port=":$RDP_ACCESS_HTTP_PORT" \
|
||||||
|
'{ if ($4 ~ (port "$")) found=1 } END { exit !found }'
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_ipv6_forward() {
|
||||||
|
[ -f "$ipv6_pid_file" ] || return 0
|
||||||
|
ipv6_pid=$(cat "$ipv6_pid_file" 2>/dev/null || true)
|
||||||
|
case $ipv6_pid in
|
||||||
|
''|*[!0-9]*) ;;
|
||||||
|
*)
|
||||||
|
if ipv6_process_matches "$ipv6_pid"; then
|
||||||
|
kill "$ipv6_pid" >/dev/null 2>&1 || true
|
||||||
|
sleep 1
|
||||||
|
if ipv6_process_matches "$ipv6_pid"; then
|
||||||
|
kill -KILL "$ipv6_pid" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
rm -f "$ipv6_pid_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
start_ipv6_forward() {
|
||||||
|
[ "$RDP_ACCESS_BIND" = 0.0.0.0 ] || return 0
|
||||||
|
case $RDP_ACCESS_IPV6_FORWARD in
|
||||||
|
never) stop_ipv6_forward; return 0 ;;
|
||||||
|
auto|always) ;;
|
||||||
|
*) fail "RDP_ACCESS_IPV6_FORWARD must be auto, always, or never" ;;
|
||||||
|
esac
|
||||||
|
if ! command -v socat >/dev/null 2>&1; then
|
||||||
|
if [ "$RDP_ACCESS_IPV6_FORWARD" = always ]; then
|
||||||
|
fail "socat is required for RDP_ACCESS_IPV6_FORWARD=always"
|
||||||
|
fi
|
||||||
|
printf 'rdp-access: warning: socat unavailable; IPv6 forwarding disabled (IPv4 remains active)\n' >&2
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if ipv6_listener_active; then
|
||||||
|
# Do not kill an unrelated listener. The operator can inspect it via
|
||||||
|
# status; down only stops a PID that this helper started and verified.
|
||||||
|
printf 'rdp-access: IPv6 port %s is already occupied; retaining the existing listener\n' \
|
||||||
|
"$RDP_ACCESS_HTTP_PORT" >&2
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
stop_ipv6_forward
|
||||||
|
umask 077
|
||||||
|
mkdir -p "$runtime_dir"
|
||||||
|
: >"$ipv6_log_file"
|
||||||
|
chmod 600 "$ipv6_log_file"
|
||||||
|
setsid nohup socat \
|
||||||
|
"TCP6-LISTEN:$RDP_ACCESS_HTTP_PORT,ipv6only=1,reuseaddr,fork,bind=$RDP_ACCESS_IPV6_BIND" \
|
||||||
|
"TCP4:127.0.0.1:$RDP_ACCESS_HTTP_PORT" \
|
||||||
|
</dev/null >>"$ipv6_log_file" 2>&1 &
|
||||||
|
ipv6_pid=$!
|
||||||
|
printf '%s\n' "$ipv6_pid" >"$ipv6_pid_file"
|
||||||
|
chmod 600 "$ipv6_pid_file"
|
||||||
|
attempts=0
|
||||||
|
while [ "$attempts" -lt 10 ]; do
|
||||||
|
if ipv6_process_matches "$ipv6_pid" && ipv6_listener_active; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
attempts=$((attempts + 1))
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
stop_ipv6_forward
|
||||||
|
if [ "$RDP_ACCESS_IPV6_FORWARD" = always ]; then
|
||||||
|
fail "could not start IPv6 forwarding listener; inspect $ipv6_log_file"
|
||||||
|
fi
|
||||||
|
printf 'rdp-access: warning: IPv6 forwarding could not start (IPv4 remains active); inspect %s\n' \
|
||||||
|
"$ipv6_log_file" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
ipv6_forward_status() {
|
||||||
|
if [ -f "$ipv6_pid_file" ] && ipv6_process_matches "$(cat "$ipv6_pid_file" 2>/dev/null || true)" && ipv6_listener_active; then
|
||||||
|
printf 'ipv6_forward=active\n'
|
||||||
|
printf 'ipv6_forward_supervisor=helper\n'
|
||||||
|
elif ipv6_listener_active; then
|
||||||
|
printf 'ipv6_forward=active_external\n'
|
||||||
|
printf 'ipv6_forward_supervisor=external\n'
|
||||||
|
elif [ "$RDP_ACCESS_BIND" != 0.0.0.0 ] || [ "$RDP_ACCESS_IPV6_FORWARD" = never ]; then
|
||||||
|
printf 'ipv6_forward=disabled\n'
|
||||||
|
else
|
||||||
|
printf 'ipv6_forward=inactive\n'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
gateway_for_network() {
|
gateway_for_network() {
|
||||||
docker network inspect --format '{{(index .IPAM.Config 0).Gateway}}' "${project}_default"
|
docker network inspect --format '{{(index .IPAM.Config 0).Gateway}}' "${project}_default"
|
||||||
}
|
}
|
||||||
@@ -340,6 +445,8 @@ safe_name RDP_ACCESS_RDP_USER "$RDP_ACCESS_RDP_USER"
|
|||||||
safe_name RVBOX_TEST_VBOX_HOST "$RVBOX_TEST_VBOX_HOST"
|
safe_name RVBOX_TEST_VBOX_HOST "$RVBOX_TEST_VBOX_HOST"
|
||||||
case $RDP_ACCESS_VRDE_HOST in 127.0.0.1|localhost) ;; *) fail "RDP_ACCESS_VRDE_HOST must be 127.0.0.1 or localhost" ;; esac
|
case $RDP_ACCESS_VRDE_HOST in 127.0.0.1|localhost) ;; *) fail "RDP_ACCESS_VRDE_HOST must be 127.0.0.1 or localhost" ;; esac
|
||||||
safe_port RDP_ACCESS_VRDE_PORT "$RDP_ACCESS_VRDE_PORT"
|
safe_port RDP_ACCESS_VRDE_PORT "$RDP_ACCESS_VRDE_PORT"
|
||||||
|
case $RDP_ACCESS_IPV6_BIND in ::|::1) ;; *) fail "RDP_ACCESS_IPV6_BIND must be :: or ::1" ;; esac
|
||||||
|
case $RDP_ACCESS_IPV6_FORWARD in auto|always|never) ;; *) fail "RDP_ACCESS_IPV6_FORWARD must be auto, always, or never" ;; esac
|
||||||
|
|
||||||
case $RDP_ACCESS_PUBLIC_HOST in
|
case $RDP_ACCESS_PUBLIC_HOST in
|
||||||
*[!0-9.]* ) cert_san="DNS:$RDP_ACCESS_PUBLIC_HOST" ;;
|
*[!0-9.]* ) cert_san="DNS:$RDP_ACCESS_PUBLIC_HOST" ;;
|
||||||
@@ -375,6 +482,7 @@ case $action in
|
|||||||
fail "existing Guacamole stack was found but the private VRDE tunnel could not be restored; inspect $tunnel_log_file"
|
fail "existing Guacamole stack was found but the private VRDE tunnel could not be restored; inspect $tunnel_log_file"
|
||||||
fi
|
fi
|
||||||
wait_for_gateway || fail "Guacamole stack is running but its HTTPS endpoint did not become ready; inspect Compose logs"
|
wait_for_gateway || fail "Guacamole stack is running but its HTTPS endpoint did not become ready; inspect Compose logs"
|
||||||
|
start_ipv6_forward
|
||||||
if [ -f "$session_file" ]; then sed -n '1p' "$session_file"; fi
|
if [ -f "$session_file" ]; then sed -n '1p' "$session_file"; fi
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
@@ -399,6 +507,7 @@ case $action in
|
|||||||
if ! wait_for_gateway; then
|
if ! wait_for_gateway; then
|
||||||
fail "Guacamole gateway started but its HTTPS endpoint did not become ready; inspect Compose logs"
|
fail "Guacamole gateway started but its HTTPS endpoint did not become ready; inspect Compose logs"
|
||||||
fi
|
fi
|
||||||
|
start_ipv6_forward
|
||||||
printf 'Guacamole is ready at https://%s:%s/guacamole/\n' "$RDP_ACCESS_PUBLIC_HOST" "$RDP_ACCESS_HTTP_PORT"
|
printf 'Guacamole is ready at https://%s:%s/guacamole/\n' "$RDP_ACCESS_PUBLIC_HOST" "$RDP_ACCESS_HTTP_PORT"
|
||||||
printf 'Accept the self-signed certificate warning, then sign in as %s with the fixture password.\n' "$RDP_ACCESS_WEB_USER"
|
printf 'Accept the self-signed certificate warning, then sign in as %s with the fixture password.\n' "$RDP_ACCESS_WEB_USER"
|
||||||
;;
|
;;
|
||||||
@@ -420,6 +529,7 @@ case $action in
|
|||||||
else
|
else
|
||||||
printf 'private_tunnel=inactive\n'
|
printf 'private_tunnel=inactive\n'
|
||||||
fi
|
fi
|
||||||
|
ipv6_forward_status
|
||||||
;;
|
;;
|
||||||
url)
|
url)
|
||||||
[ "$#" -eq 0 ] || { usage >&2; fail "url accepts no options"; }
|
[ "$#" -eq 0 ] || { usage >&2; fail "url accepts no options"; }
|
||||||
@@ -431,12 +541,14 @@ case $action in
|
|||||||
;;
|
;;
|
||||||
down)
|
down)
|
||||||
[ "$#" -eq 0 ] || { usage >&2; fail "down accepts no options"; }
|
[ "$#" -eq 0 ] || { usage >&2; fail "down accepts no options"; }
|
||||||
|
stop_ipv6_forward
|
||||||
stop_tunnel
|
stop_tunnel
|
||||||
compose down --remove-orphans || true
|
compose down --remove-orphans || true
|
||||||
printf 'Temporary gateway and private tunnel stopped; generated certificate and password hash retained in %s.\n' "$runtime_dir"
|
printf 'Temporary gateway and private tunnel stopped; generated certificate and password hash retained in %s.\n' "$runtime_dir"
|
||||||
;;
|
;;
|
||||||
clean)
|
clean)
|
||||||
[ "$#" -eq 0 ] || { usage >&2; fail "clean accepts only --images"; }
|
[ "$#" -eq 0 ] || { usage >&2; fail "clean accepts only --images"; }
|
||||||
|
stop_ipv6_forward
|
||||||
stop_tunnel
|
stop_tunnel
|
||||||
compose down --remove-orphans || true
|
compose down --remove-orphans || true
|
||||||
case $runtime_dir in "$helper_dir"/.runtime) rm -rf "$runtime_dir" ;; *) fail "unsafe runtime path" ;; esac
|
case $runtime_dir in "$helper_dir"/.runtime) rm -rf "$runtime_dir" ;; *) fail "unsafe runtime path" ;; esac
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
<param name="enable-wallpaper">false</param>
|
<param name="enable-wallpaper">false</param>
|
||||||
<param name="enable-theming">false</param>
|
<param name="enable-theming">false</param>
|
||||||
<param name="enable-font-smoothing">false</param>
|
<param name="enable-font-smoothing">false</param>
|
||||||
|
<param name="color-depth">24</param>
|
||||||
<param name="disable-gfx">true</param>
|
<param name="disable-gfx">true</param>
|
||||||
</connection>
|
</connection>
|
||||||
</authorize>
|
</authorize>
|
||||||
|
|||||||
Reference in New Issue
Block a user