aboutsummaryrefslogtreecommitdiffstats
path: root/novnc_proxy
blob: ea3ea706c7b86c68f78f13cdbfe97a8210b881fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#!/usr/bin/env bash

# Copyright (C) 2018 The noVNC Authors
# Licensed under MPL 2.0 or any later version (see LICENSE.txt)

usage() {
    if [ "$*" ]; then
        echo "$*"
        echo
    fi
    echo "Usage: ${NAME} [--listen PORT] [--vnc VNC_HOST:PORT] [--cert CERT] [--ssl-only]"
    echo
    echo "Starts the WebSockets proxy and a mini-webserver and "
    echo "provides a cut-and-paste URL to go to."
    echo
    echo "    --listen PORT         Port for proxy/webserver to listen on"
    echo "                          Default: 6080"
    echo "    --vnc VNC_HOST:PORT   VNC server host:port proxy target"
    echo "                          Default: localhost:5900"
    echo "    --cert CERT           Path to combined cert/key file, or just"
    echo "                          the cert file if used with --key"
    echo "                          Default: self.pem"
    echo "    --key KEY             Path to key file, when not combined with cert"
    echo "    --web WEB             Path to web files (e.g. vnc.html)"
    echo "                          Default: ./"
    echo "    --ssl-only            Disable non-https connections."
    echo "                                    "
    echo "    --file-only           Disable directory listing in web server."
    echo "                                    "
    echo "    --record FILE         Record traffic to FILE.session.js"
    echo "                                    "
    echo "    --syslog SERVER       Can be local socket such as /dev/log, or a UDP host:port pair."
    echo "                                    "
    echo "    --heartbeat SEC       send a ping to the client every SEC seconds"
    echo "    --timeout SEC         after SEC seconds exit when not connected"
    echo "    --idle-timeout SEC    server exits after SEC seconds if there are no"
    echo "                                    "
    echo "    --web-auth            enable authentication"
    echo "    --auth-plugin CLASS   authentication plugin to use"
    echo "    --auth-source ARG     plugin configuration"
    echo "                                    "
    echo "                          active connections"
    echo "                                    "
    exit 2
}

NAME="$(basename $0)"
REAL_NAME="$(readlink -f $0)"
HERE="$(cd "$(dirname "$REAL_NAME")" && pwd)"
PORT="6080"
VNC_DEST="localhost:5900"
CERT=""
KEY=""
WEB=""
proxy_pid=""
SSLONLY=""
RECORD_ARG=""
SYSLOG_ARG=""
HEARTBEAT_ARG=""
IDLETIMEOUT_ARG=""
TIMEOUT_ARG=""
WEBAUTH_ARG=""
AUTHPLUGIN_ARG=""
AUTHSOURCE_ARG=""
FILEONLY_ARG=""


die() {
    echo "$*"
    exit 1
}

cleanup() {
    trap - TERM QUIT INT EXIT
    trap "true" CHLD   # Ignore cleanup messages
    echo
    if [ -n "${proxy_pid}" ]; then
        echo "Terminating WebSockets proxy (${proxy_pid})"
        kill ${proxy_pid}
    fi
}

# Process Arguments

# Arguments that only apply to chrooter itself
while [ "$*" ]; do
    param=$1; shift; OPTARG=$1
    case $param in
    --listen)  PORT="${OPTARG}"; shift            ;;
    --vnc)     VNC_DEST="${OPTARG}"; shift        ;;
    --cert)    CERT="${OPTARG}"; shift            ;;
    --key)     KEY="${OPTARG}"; shift             ;;
    --web)     WEB="${OPTARG}"; shift            ;;
    --ssl-only) SSLONLY="--ssl-only"             ;;
    --file-only) FILEONLY_ARG="--file-only"      ;;
    --record) RECORD_ARG="--record ${OPTARG}"; shift ;;
    --syslog) SYSLOG_ARG="--syslog ${OPTARG}"; shift ;;
    --heartbeat) HEARTBEAT_ARG="--heartbeat ${OPTARG}"; shift ;;
    --idle-timeout) IDLETIMEOUT_ARG="--idle-timeout ${OPTARG}"; shift ;;
    --timeout) TIMEOUT_ARG="--timeout ${OPTARG}"; shift ;;
    --web-auth) WEBAUTH_ARG="--web-auth"                ;;
    --auth-plugin) AUTHPLUGIN_ARG="--auth-plugin ${OPTARG}"; shift ;;
    --auth-source) AUTHSOURCE_ARG="--auth-source ${OPTARG}"; shift ;;
    -h|--help) usage                              ;;
    -*) usage "Unknown chrooter option: ${param}" ;;
    *) break                                      ;;
    esac
done

# Sanity checks
if bash -c "exec 7<>/dev/tcp/localhost/${PORT}" &> /dev/null; then
    exec 7<&-
    exec 7>&-
    die "Port ${PORT} in use. Try --listen PORT"
else
    exec 7<&-
    exec 7>&-
fi

trap "cleanup" TERM QUIT INT EXIT

# Find vnc.html
if [ -n "${WEB}" ]; then
    if [ ! -e "${WEB}/vnc.html" ]; then
        die "Could not find ${WEB}/vnc.html"
    fi
elif [ -e "$(pwd)/vnc.html" ]; then
    WEB=$(pwd)
elif [ -e "${HERE}/../vnc.html" ]; then
    WEB=${HERE}/../
elif [ -e "${HERE}/vnc.html" ]; then
    WEB=${HERE}
elif [ -e "${HERE}/../share/novnc/vnc.html" ]; then
    WEB=${HERE}/../share/novnc/
else
    die "Could not find vnc.html"
fi

# Find self.pem
if [ -n "${CERT}" ]; then
    if [ ! -e "${CERT}" ]; then
        die "Could not find ${CERT}"
    fi
elif [ -e "$(pwd)/self.pem" ]; then
    CERT="$(pwd)/self.pem"
elif [ -e "${HERE}/../self.pem" ]; then
    CERT="${HERE}/../self.pem"
elif [ -e "${HERE}/self.pem" ]; then
    CERT="${HERE}/self.pem"
else
    echo "Warning: could not find self.pem"
fi

# Check key file
if [ -n "${KEY}" ]; then
    if [ ! -e "${KEY}" ]; then
        die "Could not find ${KEY}"
    fi
fi

# try to find websockify (prefer local, try global, then download local)
if [[ -d ${HERE}/websockify ]]; then
    WEBSOCKIFY=${HERE}/websockify/run

    if [[ ! -x $WEBSOCKIFY ]]; then
        echo "The path ${HERE}/websockify exists, but $WEBSOCKIFY either does not exist or is not executable."
        echo "If you intended to use an installed websockify package, please remove ${HERE}/websockify."
        exit 1
    fi

    echo "Using local websockify at $WEBSOCKIFY"
else
    WEBSOCKIFY_FROMSYSTEM=$(which websockify 2>/dev/null)
    WEBSOCKIFY_FROMSNAP=${HERE}/../usr/bin/python2-websockify
    [ -f $WEBSOCKIFY_FROMSYSTEM ] && WEBSOCKIFY=$WEBSOCKIFY_FROMSYSTEM
    [ -f $WEBSOCKIFY_FROMSNAP ] && WEBSOCKIFY=$WEBSOCKIFY_FROMSNAP

    if [ ! -f "$WEBSOCKIFY" ]; then
        echo "No installed websockify, attempting to clone websockify..."
        WEBSOCKIFY=${HERE}/websockify/run
        git clone https://github.com/novnc/websockify ${HERE}/websockify

        if [[ ! -e $WEBSOCKIFY ]]; then
            echo "Unable to locate ${HERE}/websockify/run after downloading"
            exit 1
        fi

        echo "Using local websockify at $WEBSOCKIFY"
    else
        echo "Using installed websockify at $WEBSOCKIFY"
    fi
fi

echo "Starting webserver and WebSockets proxy on port ${PORT}"
#${HERE}/websockify --web ${WEB} ${CERT:+--cert ${CERT}} ${PORT} ${VNC_DEST} &
${WEBSOCKIFY} ${SYSLOG_ARG} ${SSLONLY} ${FILEONLY_ARG} --web ${WEB} ${CERT:+--cert ${CERT}} ${KEY:+--key ${KEY}} ${PORT} ${VNC_DEST} ${HEARTBEAT_ARG} ${IDLETIMEOUT_ARG} ${RECORD_ARG} ${TIMEOUT_ARG} ${WEBAUTH_ARG} ${AUTHPLUGIN_ARG} ${AUTHSOURCE_ARG} &
proxy_pid="$!"
sleep 1
if [ -z "$proxy_pid" ] || ! ps -eo pid= | grep -w "$proxy_pid" > /dev/null; then
    proxy_pid=
    echo "Failed to start WebSockets proxy"
    exit 1
fi

echo -e "\n\nNavigate to this URL:\n"
if [ "x$SSLONLY" == "x" ]; then
    echo -e "    http://$(hostname):${PORT}/vnc.html?host=$(hostname)&port=${PORT}\n"
else
    echo -e "    https://$(hostname):${PORT}/vnc.html?host=$(hostname)&port=${PORT}\n"
fi

echo -e "Press Ctrl-C to exit\n\n"

wait ${proxy_pid}