opn
This commit is contained in:
1 parent
cce1081f75
commit
2b8f11ef8c
36 files changed
+1868
-309
No files matched your search
Executable
+276
@@ -0,0 +1,276 @@
|
||||
#!/bin/sh
|
||||
|
||||
# PROVIDE: rustproxy
|
||||
# REQUIRE: LOGIN NETWORKING
|
||||
# KEYWORD: shutdown
|
||||
|
||||
. /etc/rc.subr
|
||||
|
||||
name="rustproxy"
|
||||
rcvar="${name}_enable"
|
||||
|
||||
load_rc_config "$name"
|
||||
|
||||
: ${rustproxy_enable:="NO"}
|
||||
# RustProxy on OPNsense/FreeBSD runs as root. In practice the application
|
||||
# needs access to its complete data/certificate state and service startup was
|
||||
# unreliable after daemon(8) dropped privileges to the dedicated account.
|
||||
: ${rustproxy_user:="root"}
|
||||
: ${rustproxy_group:="wheel"}
|
||||
: ${rustproxy_data_dir:="/var/db/rustproxy"}
|
||||
: ${rustproxy_log_dir:="/var/log/rustproxy"}
|
||||
: ${rustproxy_log_file:="${rustproxy_log_dir}/rustproxy.log"}
|
||||
: ${rustproxy_run_dir:="/var/run/rustproxy"}
|
||||
: ${rustproxy_command:="/usr/local/sbin/rust-proxy"}
|
||||
: ${rustproxy_restart_delay:="5"}
|
||||
: ${rustproxy_allow_remote_admin:="1"}
|
||||
# FreeBSD uses jemalloc rather than glibc. Keep the same low-arena intent as
|
||||
# Linux MALLOC_ARENA_MAX=2 with the native jemalloc knob. rc.conf can override
|
||||
# rustproxy_malloc_conf or set it to an empty value to disable the tuning.
|
||||
if [ "${rustproxy_malloc_conf+x}" != "x" ]; then
|
||||
rustproxy_malloc_conf="${MALLOC_CONF:-narenas:2}"
|
||||
fi
|
||||
|
||||
# Split listener settings written by the current OPNsense model.
|
||||
: ${rustproxy_proxy_address:=""}
|
||||
: ${rustproxy_proxy_port:=""}
|
||||
: ${rustproxy_tls_enabled:="1"}
|
||||
: ${rustproxy_tls_address:=""}
|
||||
: ${rustproxy_tls_port:=""}
|
||||
: ${rustproxy_admin_address:=""}
|
||||
: ${rustproxy_admin_port:=""}
|
||||
|
||||
# Combined listener settings used by plugin model 1.2.x and earlier.
|
||||
: ${rustproxy_proxy_listen_legacy:=""}
|
||||
: ${rustproxy_tls_listen_legacy:=""}
|
||||
: ${rustproxy_admin_listen_legacy:=""}
|
||||
|
||||
# Old rc.conf-style variable names are also accepted for hand-written configs.
|
||||
: ${rustproxy_proxy_listen:=""}
|
||||
: ${rustproxy_tls_listen:=""}
|
||||
: ${rustproxy_admin_listen:=""}
|
||||
|
||||
enabled="0"
|
||||
config_file="/usr/local/etc/rustproxy/opnsense.conf"
|
||||
if [ -r "$config_file" ]; then
|
||||
. "$config_file"
|
||||
fi
|
||||
|
||||
if [ "$enabled" = "1" ]; then
|
||||
rustproxy_enable="YES"
|
||||
else
|
||||
rustproxy_enable="NO"
|
||||
fi
|
||||
|
||||
rustproxy_valid_port()
|
||||
{
|
||||
case "$1" in
|
||||
''|*[!0-9]*) return 1 ;;
|
||||
esac
|
||||
[ "$1" -ge 1 ] 2>/dev/null && [ "$1" -le 65535 ] 2>/dev/null
|
||||
}
|
||||
|
||||
rustproxy_valid_listener()
|
||||
{
|
||||
_rp_listener="$1"
|
||||
case "$_rp_listener" in
|
||||
\[*\]:*) _rp_port="${_rp_listener##*:}" ;;
|
||||
*:*) _rp_port="${_rp_listener##*:}" ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
rustproxy_valid_port "$_rp_port"
|
||||
}
|
||||
|
||||
rustproxy_format_listener()
|
||||
{
|
||||
_rp_address="$1"
|
||||
_rp_port="$2"
|
||||
case "$_rp_address" in
|
||||
\[*\]) printf '%s:%s\n' "$_rp_address" "$_rp_port" ;;
|
||||
*:*) printf '[%s]:%s\n' "$_rp_address" "$_rp_port" ;;
|
||||
*) printf '%s:%s\n' "$_rp_address" "$_rp_port" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
rustproxy_resolve_listener()
|
||||
{
|
||||
_rp_address="$1"
|
||||
_rp_port="$2"
|
||||
_rp_legacy="$3"
|
||||
_rp_old_rc="$4"
|
||||
_rp_default_address="$5"
|
||||
_rp_default_port="$6"
|
||||
_rp_name="$7"
|
||||
|
||||
# New split settings are authoritative as soon as either half is set.
|
||||
if [ -n "$_rp_address" ] || [ -n "$_rp_port" ]; then
|
||||
[ -n "$_rp_address" ] || _rp_address="$_rp_default_address"
|
||||
[ -n "$_rp_port" ] || _rp_port="$_rp_default_port"
|
||||
if ! rustproxy_valid_port "$_rp_port"; then
|
||||
echo "Invalid RustProxy ${_rp_name} port: ${_rp_port}" >&2
|
||||
return 1
|
||||
fi
|
||||
rustproxy_format_listener "$_rp_address" "$_rp_port"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Preserve a valid listener from plugin 1.2.x during upgrade.
|
||||
if [ -n "$_rp_legacy" ] && rustproxy_valid_listener "$_rp_legacy"; then
|
||||
printf '%s\n' "$_rp_legacy"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Preserve hand-written rc.conf settings as another compatibility path.
|
||||
if [ -n "$_rp_old_rc" ] && rustproxy_valid_listener "$_rp_old_rc"; then
|
||||
printf '%s\n' "$_rp_old_rc"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Malformed legacy values such as "0.0.0.0:" must never reach RustProxy.
|
||||
# Fall back to a known-good listener and let the user set the separate port
|
||||
# field in Services -> RustProxy.
|
||||
rustproxy_format_listener "$_rp_default_address" "$_rp_default_port"
|
||||
}
|
||||
|
||||
rustproxy_proxy_listen_resolved="$(rustproxy_resolve_listener \
|
||||
"$rustproxy_proxy_address" "$rustproxy_proxy_port" \
|
||||
"$rustproxy_proxy_listen_legacy" "$rustproxy_proxy_listen" \
|
||||
"0.0.0.0" "8080" "HTTP")" || exit 1
|
||||
|
||||
rustproxy_tls_listen_resolved="$(rustproxy_resolve_listener \
|
||||
"$rustproxy_tls_address" "$rustproxy_tls_port" \
|
||||
"$rustproxy_tls_listen_legacy" "$rustproxy_tls_listen" \
|
||||
"0.0.0.0" "8181" "HTTPS/TLS")" || exit 1
|
||||
|
||||
rustproxy_admin_listen_resolved="$(rustproxy_resolve_listener \
|
||||
"$rustproxy_admin_address" "$rustproxy_admin_port" \
|
||||
"$rustproxy_admin_listen_legacy" "$rustproxy_admin_listen" \
|
||||
"0.0.0.0" "9090" "admin")" || exit 1
|
||||
|
||||
rustproxy_runtime_args="--data-dir ${rustproxy_data_dir} --admin-listen ${rustproxy_admin_listen_resolved} --update-check-interval-secs 0 serve --proxy-listen ${rustproxy_proxy_listen_resolved}"
|
||||
if [ "$rustproxy_tls_enabled" = "1" ]; then
|
||||
rustproxy_runtime_args="${rustproxy_runtime_args} --tls-listen ${rustproxy_tls_listen_resolved}"
|
||||
fi
|
||||
if [ "$rustproxy_allow_remote_admin" = "1" ]; then
|
||||
rustproxy_runtime_args="${rustproxy_runtime_args} --allow-remote-admin"
|
||||
fi
|
||||
|
||||
pidfile="${rustproxy_run_dir}/daemon.pid"
|
||||
child_pidfile="${rustproxy_run_dir}/rustproxy.pid"
|
||||
command="/usr/sbin/daemon"
|
||||
|
||||
rustproxy_daemon_user_arg=""
|
||||
if [ "$rustproxy_user" != "root" ]; then
|
||||
rustproxy_daemon_user_arg="-u ${rustproxy_user}"
|
||||
fi
|
||||
command_args="-r -R ${rustproxy_restart_delay} -P ${pidfile} -p ${child_pidfile} ${rustproxy_daemon_user_arg} -o ${rustproxy_log_file} ${rustproxy_command} ${rustproxy_runtime_args}"
|
||||
required_files="${rustproxy_command}"
|
||||
start_precmd="rustproxy_prestart"
|
||||
start_postcmd="rustproxy_poststart"
|
||||
stop_postcmd="rustproxy_poststop"
|
||||
status_cmd="rustproxy_status"
|
||||
|
||||
rustproxy_prestart()
|
||||
{
|
||||
# RustProxy on OPNsense/FreeBSD uses jemalloc. MALLOC_ARENA_MAX is a
|
||||
# glibc/Linux setting and has no useful effect here, so export MALLOC_CONF
|
||||
# instead. daemon(8) inherits this environment and passes it to RustProxy.
|
||||
if [ -n "${rustproxy_malloc_conf}" ]; then
|
||||
MALLOC_CONF="${rustproxy_malloc_conf}"
|
||||
export MALLOC_CONF
|
||||
else
|
||||
unset MALLOC_CONF
|
||||
fi
|
||||
|
||||
# /var/run is ephemeral and recreated on boot.
|
||||
/usr/bin/install -d -o "${rustproxy_user}" -g "${rustproxy_group}" -m 0750 "${rustproxy_run_dir}"
|
||||
/usr/sbin/chown "${rustproxy_user}:${rustproxy_group}" "${rustproxy_run_dir}"
|
||||
/bin/chmod 0750 "${rustproxy_run_dir}"
|
||||
|
||||
/usr/bin/install -d -o "${rustproxy_user}" -g "${rustproxy_group}" -m 0700 "${rustproxy_data_dir}"
|
||||
/usr/sbin/chown "${rustproxy_user}:${rustproxy_group}" "${rustproxy_data_dir}"
|
||||
/bin/chmod 0700 "${rustproxy_data_dir}"
|
||||
|
||||
/usr/bin/install -d -o "${rustproxy_user}" -g "${rustproxy_group}" -m 0750 "${rustproxy_log_dir}"
|
||||
/usr/bin/touch "${rustproxy_log_file}"
|
||||
/usr/sbin/chown "${rustproxy_user}:${rustproxy_group}" "${rustproxy_log_file}"
|
||||
/bin/chmod 0640 "${rustproxy_log_file}"
|
||||
|
||||
echo "RustProxy listeners: HTTP=${rustproxy_proxy_listen_resolved} TLS=${rustproxy_tls_listen_resolved} ADMIN=${rustproxy_admin_listen_resolved}"
|
||||
if [ -n "${rustproxy_malloc_conf}" ]; then
|
||||
echo "RustProxy allocator: MALLOC_CONF=${rustproxy_malloc_conf}"
|
||||
fi
|
||||
echo "RustProxy exec: ${rustproxy_command} ${rustproxy_runtime_args}"
|
||||
printf '%s\n' "${rustproxy_command} ${rustproxy_runtime_args}" > "${rustproxy_run_dir}/command.txt"
|
||||
/bin/chmod 0640 "${rustproxy_run_dir}/command.txt"
|
||||
}
|
||||
|
||||
rustproxy_child_pid()
|
||||
{
|
||||
[ -r "${child_pidfile}" ] || return 1
|
||||
_rp_pid="$(/bin/cat "${child_pidfile}" 2>/dev/null)"
|
||||
case "${_rp_pid}" in
|
||||
''|*[!0-9]*) return 1 ;;
|
||||
esac
|
||||
/bin/kill -0 "${_rp_pid}" 2>/dev/null || return 1
|
||||
printf '%s\n' "${_rp_pid}"
|
||||
}
|
||||
|
||||
rustproxy_poststart()
|
||||
{
|
||||
# daemon(8) may stay alive with -r even when rust-proxy exits immediately.
|
||||
# Verify the supervised child so service/configd cannot report a false OK.
|
||||
/bin/sleep 1
|
||||
if _rp_pid="$(rustproxy_child_pid)"; then
|
||||
echo "RustProxy child started as PID ${_rp_pid}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "RustProxy failed to stay running; stopping the restart supervisor." >&2
|
||||
if [ -s "${rustproxy_log_file}" ]; then
|
||||
echo "Last RustProxy log lines:" >&2
|
||||
/usr/bin/tail -n 40 "${rustproxy_log_file}" >&2
|
||||
fi
|
||||
if [ -r "${pidfile}" ]; then
|
||||
_rp_supervisor_pid="$(/bin/cat "${pidfile}" 2>/dev/null)"
|
||||
case "${_rp_supervisor_pid}" in
|
||||
''|*[!0-9]*) ;;
|
||||
*) /bin/kill -TERM "${_rp_supervisor_pid}" 2>/dev/null || true ;;
|
||||
esac
|
||||
fi
|
||||
/bin/sleep 1
|
||||
/bin/rm -f "${child_pidfile}" "${pidfile}"
|
||||
return 1
|
||||
}
|
||||
|
||||
rustproxy_status()
|
||||
{
|
||||
if _rp_pid="$(rustproxy_child_pid)"; then
|
||||
echo "rustproxy is running as pid ${_rp_pid}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_rp_supervisor_pid=""
|
||||
if [ -r "${pidfile}" ]; then
|
||||
_rp_supervisor_pid="$(/bin/cat "${pidfile}" 2>/dev/null)"
|
||||
fi
|
||||
case "${_rp_supervisor_pid}" in
|
||||
''|*[!0-9]*) ;;
|
||||
*)
|
||||
if /bin/kill -0 "${_rp_supervisor_pid}" 2>/dev/null; then
|
||||
echo "rustproxy is not running (daemon supervisor ${_rp_supervisor_pid} is waiting/restarting)"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "rustproxy is not running"
|
||||
return 1
|
||||
}
|
||||
|
||||
rustproxy_poststop()
|
||||
{
|
||||
/bin/rm -f "${child_pidfile}" "${pidfile}"
|
||||
}
|
||||
|
||||
run_rc_command "$1"
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
/usr/local/sbin/configctl template reload OPNsense/RustProxy >/dev/null 2>&1 || true
|
||||
/usr/local/sbin/configctl rustproxy boot >/dev/null 2>&1 || true
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace OPNsense\RustProxy\Api;
|
||||
|
||||
use OPNsense\Base\ApiMutableServiceControllerBase;
|
||||
|
||||
class ServiceController extends ApiMutableServiceControllerBase
|
||||
{
|
||||
protected static $internalServiceClass = '\\OPNsense\\RustProxy\\RustProxy';
|
||||
protected static $internalServiceTemplate = 'OPNsense/RustProxy';
|
||||
protected static $internalServiceEnabled = 'general.enabled';
|
||||
protected static $internalServiceName = 'rustproxy';
|
||||
|
||||
protected function reconfigureForceRestart()
|
||||
{
|
||||
// Listener addresses are process startup arguments, so Apply must
|
||||
// always stop and start the service after regenerating the template.
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace OPNsense\RustProxy\Api;
|
||||
|
||||
use OPNsense\Base\ApiMutableModelControllerBase;
|
||||
|
||||
class SettingsController extends ApiMutableModelControllerBase
|
||||
{
|
||||
protected static $internalModelClass = 'OPNsense\RustProxy\RustProxy';
|
||||
protected static $internalModelName = 'rustproxy';
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace OPNsense\RustProxy;
|
||||
|
||||
class IndexController extends \OPNsense\Base\IndexController
|
||||
{
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->generalForm = $this->getForm('general');
|
||||
$this->view->pick('OPNsense/RustProxy/index');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<form>
|
||||
<field>
|
||||
<label>General</label>
|
||||
<type>header</type>
|
||||
<static>true</static>
|
||||
</field>
|
||||
<field>
|
||||
<id>rustproxy.general.enabled</id>
|
||||
<label>Enabled</label>
|
||||
<type>checkbox</type>
|
||||
<help>Start RustProxy and keep it enabled after OPNsense restarts.</help>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<label>HTTP listener</label>
|
||||
<type>header</type>
|
||||
<static>true</static>
|
||||
</field>
|
||||
<field>
|
||||
<id>rustproxy.general.proxyAddress</id>
|
||||
<label>Bind address</label>
|
||||
<type>text</type>
|
||||
<help>HTTP bind address. Default: 0.0.0.0. Existing installations are migrated from the legacy combined listener automatically.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rustproxy.general.proxyPort</id>
|
||||
<label>Port</label>
|
||||
<type>text</type>
|
||||
<help>HTTP port passed as --proxy-listen. Default: 8080.</help>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<label>HTTPS/TLS listener</label>
|
||||
<type>header</type>
|
||||
<static>true</static>
|
||||
</field>
|
||||
<field>
|
||||
<id>rustproxy.general.tlsEnabled</id>
|
||||
<label>Enable HTTPS/TLS listener</label>
|
||||
<type>checkbox</type>
|
||||
<help>When enabled, pass --tls-listen to RustProxy.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rustproxy.general.tlsAddress</id>
|
||||
<label>Bind address</label>
|
||||
<type>text</type>
|
||||
<help>HTTPS/TLS bind address. Default: 0.0.0.0. Existing installations are migrated automatically.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rustproxy.general.tlsPort</id>
|
||||
<label>Port</label>
|
||||
<type>text</type>
|
||||
<help>HTTPS/TLS port passed as --tls-listen. Default: 8181.</help>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<label>Administration</label>
|
||||
<type>header</type>
|
||||
<static>true</static>
|
||||
</field>
|
||||
<field>
|
||||
<id>rustproxy.general.adminAddress</id>
|
||||
<label>Bind address</label>
|
||||
<type>text</type>
|
||||
<help>Administration bind address. Default: 0.0.0.0. Existing installations are migrated automatically.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rustproxy.general.adminPort</id>
|
||||
<label>Port</label>
|
||||
<type>text</type>
|
||||
<help>Administration port passed as --admin-listen. Default: 9090.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rustproxy.general.allowRemoteAdmin</id>
|
||||
<label>Allow remote admin</label>
|
||||
<type>checkbox</type>
|
||||
<help>Pass --allow-remote-admin so the RustProxy panel accepts non-loopback clients. Keep firewall access restricted to trusted networks; do not expose the admin port to WAN unless this is intentional.</help>
|
||||
</field>
|
||||
</form>
|
||||
@@ -0,0 +1,10 @@
|
||||
<acl>
|
||||
<page-services-rustproxy>
|
||||
<name>Services: RustProxy</name>
|
||||
<description>Allow access to RustProxy settings and service controls</description>
|
||||
<patterns>
|
||||
<pattern>ui/rustproxy/*</pattern>
|
||||
<pattern>api/rustproxy/*</pattern>
|
||||
</patterns>
|
||||
</page-services-rustproxy>
|
||||
</acl>
|
||||
@@ -0,0 +1,7 @@
|
||||
<menu>
|
||||
<Services>
|
||||
<RustProxy cssClass="fa fa-exchange fa-fw">
|
||||
<General VisibleName="General" order="10" url="/ui/rustproxy/"/>
|
||||
</RustProxy>
|
||||
</Services>
|
||||
</menu>
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace OPNsense\RustProxy\Migrations;
|
||||
|
||||
use OPNsense\Base\BaseModelMigration;
|
||||
|
||||
/**
|
||||
* Repair the 1.3.x split-listener transition.
|
||||
*
|
||||
* 1.2.x stored listeners as a single IP:port field. The first 1.3.x package
|
||||
* introduced address/port fields without model defaults, so an upgrade could
|
||||
* save fallback/new values while the still-valid legacy values remained in
|
||||
* config.xml. Copy the legacy values once into the split fields so existing
|
||||
* installations keep the exact ports they used before the upgrade.
|
||||
*/
|
||||
class M1_4_0 extends BaseModelMigration
|
||||
{
|
||||
private function splitListener($value)
|
||||
{
|
||||
$value = trim((string)$value);
|
||||
if ($value === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (preg_match('/^\[([^\]]+)\]:(\d+)$/', $value, $matches)) {
|
||||
$address = $matches[1];
|
||||
$port = $matches[2];
|
||||
} else {
|
||||
$separator = strrpos($value, ':');
|
||||
if ($separator === false) {
|
||||
return null;
|
||||
}
|
||||
$address = substr($value, 0, $separator);
|
||||
$port = substr($value, $separator + 1);
|
||||
}
|
||||
|
||||
if ($address === '' || !ctype_digit($port)) {
|
||||
return null;
|
||||
}
|
||||
$number = (int)$port;
|
||||
if ($number < 1 || $number > 65535) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [$address, (string)$number];
|
||||
}
|
||||
|
||||
private function migrateListener($general, $legacyField, $addressField, $portField)
|
||||
{
|
||||
$parts = $this->splitListener((string)$general->$legacyField);
|
||||
if ($parts === null) {
|
||||
return;
|
||||
}
|
||||
$general->$addressField = $parts[0];
|
||||
$general->$portField = $parts[1];
|
||||
}
|
||||
|
||||
public function run($model)
|
||||
{
|
||||
parent::run($model);
|
||||
|
||||
// Deliberately prefer valid 1.2.x values during this one migration.
|
||||
// This also repairs hosts that already installed the broken 1.3.x model.
|
||||
$this->migrateListener($model->general, 'proxyListen', 'proxyAddress', 'proxyPort');
|
||||
$this->migrateListener($model->general, 'tlsListen', 'tlsAddress', 'tlsPort');
|
||||
$this->migrateListener($model->general, 'adminListen', 'adminAddress', 'adminPort');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace OPNsense\RustProxy;
|
||||
|
||||
use OPNsense\Base\BaseModel;
|
||||
|
||||
class RustProxy extends BaseModel
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<model>
|
||||
<mount>//OPNsense/rustproxy</mount>
|
||||
<version>1.4.0</version>
|
||||
<description>RustProxy service settings</description>
|
||||
<items>
|
||||
<general>
|
||||
<enabled type="BooleanField">
|
||||
<Default>0</Default>
|
||||
<Required>Y</Required>
|
||||
</enabled>
|
||||
|
||||
<!--
|
||||
Listener address/port are intentionally stored as separate fields.
|
||||
OPNsense/FreeBSD installations in the field have produced malformed
|
||||
combined IP:port values (for example 0.0.0.0:) when IPPortField is
|
||||
round-tripped through config.xml/templates. Keep the old combined
|
||||
fields below for upgrade compatibility, but new UI writes these.
|
||||
-->
|
||||
<proxyAddress type="NetworkField">
|
||||
<Default>0.0.0.0</Default>
|
||||
<Required>Y</Required>
|
||||
<NetMaskAllowed>N</NetMaskAllowed>
|
||||
<ValidationMessage>Enter a valid HTTP bind address, for example 0.0.0.0.</ValidationMessage>
|
||||
</proxyAddress>
|
||||
<proxyPort type="PortField">
|
||||
<Default>8080</Default>
|
||||
<Required>Y</Required>
|
||||
<ValidationMessage>Enter a valid HTTP port between 1 and 65535.</ValidationMessage>
|
||||
</proxyPort>
|
||||
<tlsEnabled type="BooleanField">
|
||||
<Default>1</Default>
|
||||
<Required>Y</Required>
|
||||
</tlsEnabled>
|
||||
<tlsAddress type="NetworkField">
|
||||
<Default>0.0.0.0</Default>
|
||||
<Required>Y</Required>
|
||||
<NetMaskAllowed>N</NetMaskAllowed>
|
||||
<ValidationMessage>Enter a valid HTTPS/TLS bind address, for example 0.0.0.0.</ValidationMessage>
|
||||
</tlsAddress>
|
||||
<tlsPort type="PortField">
|
||||
<Default>8181</Default>
|
||||
<Required>Y</Required>
|
||||
<ValidationMessage>Enter a valid HTTPS/TLS port between 1 and 65535.</ValidationMessage>
|
||||
</tlsPort>
|
||||
<adminAddress type="NetworkField">
|
||||
<Default>0.0.0.0</Default>
|
||||
<Required>Y</Required>
|
||||
<NetMaskAllowed>N</NetMaskAllowed>
|
||||
<ValidationMessage>Enter a valid administration bind address, for example 0.0.0.0.</ValidationMessage>
|
||||
</adminAddress>
|
||||
<adminPort type="PortField">
|
||||
<Default>9090</Default>
|
||||
<Required>Y</Required>
|
||||
<ValidationMessage>Enter a valid administration port between 1 and 65535.</ValidationMessage>
|
||||
</adminPort>
|
||||
<allowRemoteAdmin type="BooleanField">
|
||||
<Default>1</Default>
|
||||
<Required>Y</Required>
|
||||
</allowRemoteAdmin>
|
||||
|
||||
<!-- Legacy combined listener values retained for seamless upgrades. -->
|
||||
<proxyListen type="IPPortField"/>
|
||||
<tlsListen type="IPPortField"/>
|
||||
<adminListen type="IPPortField"/>
|
||||
</general>
|
||||
</items>
|
||||
</model>
|
||||
@@ -0,0 +1,141 @@
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
function parseAdminListen(value) {
|
||||
value = (value || '').trim();
|
||||
if (value.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Bracketed IPv6, for example [2001:db8::1]:9090.
|
||||
if (value.charAt(0) === '[') {
|
||||
const end = value.indexOf(']');
|
||||
if (end === -1 || value.charAt(end + 1) !== ':') {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
host: value.substring(1, end),
|
||||
port: value.substring(end + 2)
|
||||
};
|
||||
}
|
||||
|
||||
const separator = value.lastIndexOf(':');
|
||||
if (separator <= 0) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
host: value.substring(0, separator),
|
||||
port: value.substring(separator + 1)
|
||||
};
|
||||
}
|
||||
|
||||
function formatUrlHost(host) {
|
||||
return host.indexOf(':') !== -1 ? '[' + host + ']' : host;
|
||||
}
|
||||
|
||||
function openRustProxyAdmin() {
|
||||
$.getJSON('/api/rustproxy/settings/get')
|
||||
.done(function(data) {
|
||||
const general = data && data.rustproxy && data.rustproxy.general
|
||||
? data.rustproxy.general
|
||||
: {};
|
||||
let listen = null;
|
||||
const adminAddress = String(general.adminAddress || '').trim();
|
||||
const adminPort = String(general.adminPort || '').trim();
|
||||
if (adminAddress || adminPort) {
|
||||
listen = {
|
||||
host: adminAddress || '0.0.0.0',
|
||||
port: adminPort || '9090'
|
||||
};
|
||||
} else {
|
||||
// Upgrade compatibility with plugin model 1.2.x.
|
||||
listen = parseAdminListen(general.adminListen || '0.0.0.0:9090');
|
||||
}
|
||||
const remoteValue = general.allowRemoteAdmin;
|
||||
const allowRemote = remoteValue === true || remoteValue === 1 ||
|
||||
['1', 'true', 'yes', 'on'].indexOf(String(remoteValue || '').toLowerCase()) !== -1;
|
||||
|
||||
if (!listen || !listen.port) {
|
||||
BootstrapDialog.alert('{{ lang._("Invalid RustProxy admin listener configuration.") }}');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!allowRemote) {
|
||||
BootstrapDialog.alert('{{ lang._("Enable Allow remote admin and Apply the configuration before opening the RustProxy panel from another host.") }}');
|
||||
return;
|
||||
}
|
||||
|
||||
let targetHost = listen.host;
|
||||
if (targetHost === '0.0.0.0' || targetHost === '::' || targetHost === '*') {
|
||||
targetHost = window.location.hostname;
|
||||
}
|
||||
|
||||
if (targetHost === '127.0.0.1' || targetHost === 'localhost' || targetHost === '::1') {
|
||||
BootstrapDialog.alert('{{ lang._("The RustProxy admin listener is bound to loopback only. Set Admin listen to an address reachable from your network, for example 0.0.0.0:9090, then Apply.") }}');
|
||||
return;
|
||||
}
|
||||
|
||||
const url = 'http://' + formatUrlHost(targetHost) + ':' + listen.port + '/';
|
||||
const adminWindow = window.open(url, '_blank');
|
||||
if (adminWindow) {
|
||||
adminWindow.opener = null;
|
||||
}
|
||||
})
|
||||
.fail(function() {
|
||||
BootstrapDialog.alert('{{ lang._("Unable to read RustProxy settings.") }}');
|
||||
});
|
||||
}
|
||||
|
||||
mapDataToFormUI({'frm_GeneralSettings': '/api/rustproxy/settings/get'}).done(function() {
|
||||
updateServiceControlUI('rustproxy');
|
||||
});
|
||||
|
||||
$('#reconfigureAct').SimpleActionButton({
|
||||
onPreAction: function() {
|
||||
const deferred = new $.Deferred();
|
||||
saveFormToEndpoint(
|
||||
'/api/rustproxy/settings/set',
|
||||
'frm_GeneralSettings',
|
||||
function() { deferred.resolve(); },
|
||||
true,
|
||||
function() { deferred.reject(); }
|
||||
);
|
||||
return deferred;
|
||||
},
|
||||
onAction: function() {
|
||||
updateServiceControlUI('rustproxy');
|
||||
}
|
||||
});
|
||||
|
||||
$('#openAdminAct').click(function() {
|
||||
openRustProxyAdmin();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<section class="page-content-main">
|
||||
<div class="content-box">
|
||||
{{ partial("layout_partials/base_form", ['fields': generalForm, 'id': 'frm_GeneralSettings']) }}
|
||||
</div>
|
||||
<br/>
|
||||
<div class="content-box">
|
||||
<div class="col-md-12">
|
||||
<br/>
|
||||
<button class="btn btn-primary"
|
||||
id="reconfigureAct"
|
||||
data-endpoint="/api/rustproxy/service/reconfigure"
|
||||
data-label="{{ lang._('Apply') }}"
|
||||
data-error-title="{{ lang._('Error reconfiguring RustProxy') }}"
|
||||
type="button"></button>
|
||||
<button class="btn btn-default"
|
||||
id="openAdminAct"
|
||||
type="button">
|
||||
<span class="fa fa-external-link"></span>
|
||||
{{ lang._('Open RustProxy Admin') }}
|
||||
</button>
|
||||
<br/><br/>
|
||||
<p class="help-block">
|
||||
{{ lang._('Remote administration is controlled by the RustProxy listener and OPNsense firewall rules. The plugin does not automatically create a WAN firewall rule for the admin port.') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,45 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -u
|
||||
|
||||
CONFIG_FILE="/usr/local/etc/rustproxy/opnsense.conf"
|
||||
RC_SCRIPT="/usr/local/etc/rc.d/rustproxy"
|
||||
enabled="0"
|
||||
|
||||
if [ -r "$CONFIG_FILE" ]; then
|
||||
. "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
start_service()
|
||||
{
|
||||
if [ "$enabled" != "1" ]; then
|
||||
echo "RustProxy is disabled in OPNsense configuration"
|
||||
return 0
|
||||
fi
|
||||
"$RC_SCRIPT" onestart
|
||||
}
|
||||
|
||||
stop_service()
|
||||
{
|
||||
"$RC_SCRIPT" onestop >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
start|boot)
|
||||
start_service
|
||||
;;
|
||||
stop)
|
||||
stop_service
|
||||
;;
|
||||
restart|reload)
|
||||
stop_service
|
||||
start_service
|
||||
;;
|
||||
status)
|
||||
"$RC_SCRIPT" status
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 {start|stop|restart|reload|status|boot}" >&2
|
||||
exit 64
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,42 @@
|
||||
[start]
|
||||
command:/usr/local/opnsense/scripts/rustproxy/service.sh start
|
||||
parameters:
|
||||
type:script
|
||||
message:starting RustProxy
|
||||
allowed_groups:wheel,wwwonly
|
||||
|
||||
[stop]
|
||||
command:/usr/local/opnsense/scripts/rustproxy/service.sh stop
|
||||
parameters:
|
||||
type:script
|
||||
message:stopping RustProxy
|
||||
allowed_groups:wheel,wwwonly
|
||||
|
||||
[restart]
|
||||
command:/usr/local/opnsense/scripts/rustproxy/service.sh restart
|
||||
parameters:
|
||||
type:script
|
||||
message:restarting RustProxy
|
||||
allowed_groups:wheel,wwwonly
|
||||
|
||||
[reload]
|
||||
command:/usr/local/opnsense/scripts/rustproxy/service.sh restart
|
||||
parameters:
|
||||
type:script
|
||||
message:reloading RustProxy
|
||||
allowed_groups:wheel,wwwonly
|
||||
|
||||
[status]
|
||||
command:/usr/local/opnsense/scripts/rustproxy/service.sh status
|
||||
parameters:
|
||||
type:script_output
|
||||
errors:no
|
||||
message:RustProxy status
|
||||
allowed_groups:wheel,wwwonly
|
||||
|
||||
[boot]
|
||||
command:/usr/local/opnsense/scripts/rustproxy/service.sh boot
|
||||
parameters:
|
||||
type:script
|
||||
message:starting RustProxy at boot
|
||||
allowed_groups:wheel,wwwonly
|
||||
@@ -0,0 +1 @@
|
||||
rustproxy.conf:/usr/local/etc/rustproxy/opnsense.conf
|
||||
@@ -0,0 +1,18 @@
|
||||
enabled="{% if not helpers.empty('OPNsense.rustproxy.general.enabled') %}1{% else %}0{% endif %}"
|
||||
|
||||
# New split listener fields. Empty values are resolved by rc.d using the
|
||||
# legacy combined field (upgrade path) and finally the built-in defaults.
|
||||
rustproxy_proxy_address="{% if not helpers.empty('OPNsense.rustproxy.general.proxyAddress') %}{{ OPNsense.rustproxy.general.proxyAddress }}{% endif %}"
|
||||
rustproxy_proxy_port="{% if not helpers.empty('OPNsense.rustproxy.general.proxyPort') %}{{ OPNsense.rustproxy.general.proxyPort }}{% endif %}"
|
||||
rustproxy_tls_enabled="{% if not helpers.empty('OPNsense.rustproxy.general.tlsEnabled') %}1{% else %}0{% endif %}"
|
||||
rustproxy_tls_address="{% if not helpers.empty('OPNsense.rustproxy.general.tlsAddress') %}{{ OPNsense.rustproxy.general.tlsAddress }}{% endif %}"
|
||||
rustproxy_tls_port="{% if not helpers.empty('OPNsense.rustproxy.general.tlsPort') %}{{ OPNsense.rustproxy.general.tlsPort }}{% endif %}"
|
||||
rustproxy_admin_address="{% if not helpers.empty('OPNsense.rustproxy.general.adminAddress') %}{{ OPNsense.rustproxy.general.adminAddress }}{% endif %}"
|
||||
rustproxy_admin_port="{% if not helpers.empty('OPNsense.rustproxy.general.adminPort') %}{{ OPNsense.rustproxy.general.adminPort }}{% endif %}"
|
||||
rustproxy_allow_remote_admin="{% if not helpers.empty('OPNsense.rustproxy.general.allowRemoteAdmin') %}1{% else %}0{% endif %}"
|
||||
|
||||
# Legacy 1.2.x combined settings. They are only used when the corresponding
|
||||
# new split address/port fields are both empty.
|
||||
rustproxy_proxy_listen_legacy="{% if not helpers.empty('OPNsense.rustproxy.general.proxyListen') %}{{ OPNsense.rustproxy.general.proxyListen }}{% endif %}"
|
||||
rustproxy_tls_listen_legacy="{% if not helpers.empty('OPNsense.rustproxy.general.tlsListen') %}{{ OPNsense.rustproxy.general.tlsListen }}{% endif %}"
|
||||
rustproxy_admin_listen_legacy="{% if not helpers.empty('OPNsense.rustproxy.general.adminListen') %}{{ OPNsense.rustproxy.general.adminListen }}{% endif %}"
|
||||
Reference in new issue
Block a user