You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

408 lines
8.2 KiB

#!/bin/sh /etc/rc.common
# Copyright (C) 2006-2008 OpenWrt.org
# Copyright (C) 2019 Jeffery To
START=90
USE_PROCD=1
PID_FILE="/var/run/stunnel/stunnel.pid"
CONF_FILE="/var/etc/stunnel.conf"
BIN="/usr/bin/stunnel"
CONF_FILE_CREATED=
HAVE_ALT_CONF_FILE=
SERVICE_SECTION_FOUND=
validate_globals_section() {
uci_load_validate stunnel globals "$1" "$2" \
'alt_config_file:file' \
\
'compression:or("deflate","zlib")' \
'EGD:string' \
'engine:string' \
'engineCtrl:string' \
'engineDefault:list(or("ALL","CIPHERS","DH","DIGESTS","DSA","ECDH","ECDSA","PKEY","PKEY_ASN1","PKEY_CRYPTO","RAND","RSA"))' \
'log:or("append","overwrite")' \
'output:string' \
'RNDbytes:uinteger' \
'RNDfile:string' \
'RNDoverwrite:bool' \
'setgid:or(string,uinteger)' \
'setuid:or(string,uinteger)' \
'syslog:bool' \
;
}
validate_service_section() {
uci_load_validate stunnel service "$1" "$2" \
'enabled:bool:1' \
\
'setgid:or(string,uinteger)' \
'setuid:or(string,uinteger)' \
;
}
validate_service_options() {
uci_load_validate stunnel "$1" "$2" "$3" \
'accept_host:host' \
'accept_port:port' \
'CAfile:string' \
'CApath:string' \
'cert:string' \
'checkEmail:list(string)' \
'checkHost:list(host)' \
'checkIP:list(ipaddr)' \
'ciphers:list(string)' \
'ciphersuites:list(string)' \
'client:bool' \
'config:list(string)' \
'connect:list(string)' \
'CRLfile:string' \
'CRLpath:string' \
'curves:list(string)' \
'debug:or(range(0,7),string)' \
'delay:bool' \
'engineId:string' \
'engineNum:and(uinteger,min(1))' \
'exec:string' \
'execArgs:string' \
'failover:or("prio","rr")' \
'ident:string' \
'include:directory' \
'key:string' \
'local:host' \
'logId:or("process","sequential","thread","unique")' \
'OCSP:string' \
'OCSPaia:bool' \
'OCSPflag:list(or("NOCASIGN","NOCERTS","NOCHAIN","NOCHECKS","NODELEGATED","NOEXPLICIT","NOINTERN","NOSIGS","NOTIME","NOVERIFY","RESPID_KEY","TRUSTOTHER"))' \
'OCSPnonce:bool' \
'options:list(string) ' \
'protocol:or("cifs","connect","imap","nntp","pgsql","pop3","proxy","smtp","socks")' \
'protocolAuthentication:or("basic","login","ntlm","plain")' \
'protocolDomain:hostname' \
'protocolHost_host:host' \
'protocolHost_port:port' \
'protocolPassword:string' \
'protocolUsername:string' \
'PSKidentity:string' \
'PSKsecrets:string' \
'pty:bool' \
'redirect_host:host' \
'redirect_port:port' \
'renegotiation:bool' \
'requireCert:bool' \
'reset:bool' \
'retry:bool' \
'service:string' \
'sessionCacheSize:uinteger' \
'sessionCacheTimeout:uinteger' \
'sessiond_host:host' \
'sessiond_port:port' \
'sni:list(string)' \
'socket:list(string)' \
'sslVersion:or("all","SSLv2","SSLv3","TLSv1","TLSv1.1","TLSv1.2")' \
'stack:uinteger' \
'ticketKeySecret:string' \
'ticketMacSecret:string' \
'TIMEOUTbusy:uinteger' \
'TIMEOUTclose:uinteger' \
'TIMEOUTconnect:uinteger' \
'TIMEOUTidle:uinteger' \
'transparent:or("both","destination","none","source")' \
'verifyChain:bool' \
'verifyPeer:bool' \
;
}
validate_globals_section_service_options() {
validate_service_options globals "$@"
}
validate_service_section_service_options() {
validate_service_options service "$@"
}
print_options() {
local _opt
local _value
for _opt in $*; do
eval "_value=\$$_opt"
[ -z "$_value" ] || echo "$_opt = $_value" >> "$CONF_FILE"
done
}
print_bool_options() {
local _opt
local _bool
local _value
for _opt in $*; do
eval "_bool=\$$_opt"
[ -z "$_bool" ] || {
_value=no
[ "$_bool" != 1 ] || _value=yes
echo "$_opt = $_value" >> "$CONF_FILE"
}
done
}
print_lists_map() {
local _opt
local _values
local _value
for _opt in $*; do
eval "_values=\$$_opt"
for _value in $_values; do
echo "$_opt = $_value" >> "$CONF_FILE"
done
done
}
print_lists_reduce() {
local _delim="$1"
local _opt
local _value
local _values
local _v
shift
for _opt in $*; do
_value=
eval "_values=\$$_opt"
for _v in $_values; do
_value=$_value$_delim$_v
done
_value=${_value#$_delim}
[ -z "$_value" ] || echo "$_opt = $_value" >> "$CONF_FILE"
done
}
print_host_port() {
local _opt
local _host
local _port
for _opt in $*; do
eval "_host=\${${_opt}_host}"
eval "_port=\${${_opt}_port}"
[ -z "$_host" ] || [ -z "$_port" ] || echo "$_opt = $_host:$_port" >> "$CONF_FILE"
done
}
print_optional_host_port() {
local _opt
local _host
local _port
local _value
for _opt in $*; do
eval "_host=\${${_opt}_host}"
eval "_port=\${${_opt}_port}"
[ -z "$_port" ] || {
_value=$_port
[ -z "$_host" ] || _value=$_host:$_port
echo "$_opt = $_value" >> "$CONF_FILE"
}
done
}
print_global_options() {
print_options \
compression \
EGD \
engine \
engineCtrl \
log \
output \
RNDbytes \
RNDfile \
RNDoverwrite \
;
print_bool_options \
syslog \
;
print_lists_reduce , \
engineDefault \
;
}
print_service_options() {
[ "$2" = 0 ] || {
echo "validation failed"
return 1
}
print_options \
CAfile \
CApath \
cert \
CRLfile \
CRLpath \
debug \
logId \
engineId \
engineNum \
exec \
execArgs \
failover \
ident \
include \
key \
local \
OCSP \
protocol \
protocolAuthentication \
protocolDomain \
protocolPassword \
protocolUsername \
PSKidentity \
PSKsecrets \
service \
sessionCacheSize \
sessionCacheTimeout \
setgid \
setuid \
sslVersion \
stack \
ticketKeySecret \
ticketMacSecret \
TIMEOUTbusy \
TIMEOUTclose \
TIMEOUTconnect \
TIMEOUTidle \
transparent \
;
print_bool_options \
client \
delay \
OCSPaia \
OCSPnonce \
pty \
renegotiation \
requireCert \
reset \
retry \
verifyChain \
verifyPeer \
;
print_lists_map \
checkEmail \
checkHost \
checkIP \
config \
connect \
OCSPflag \
options \
sni \
socket \
;
print_lists_reduce : \
ciphers \
curves \
ciphersuites \
;
print_host_port \
protocolHost \
sessiond \
;
print_optional_host_port \
accept \
redirect \
;
}
create_conf_file() {
[ -n "$CONF_FILE_CREATED" ] || {
mkdir -p "$(dirname "$CONF_FILE")"
echo "; STunnel configuration file generated by uci" > "$CONF_FILE"
echo "; Written $(date +'%c')" >> "$CONF_FILE"
echo >> "$CONF_FILE"
echo "foreground = quiet" >> "$CONF_FILE"
echo "pid = $PID_FILE" >> "$CONF_FILE"
CONF_FILE_CREATED=1
}
}
global_defs() {
local pid_dir
[ "$2" = 0 ] || {
echo "validation failed"
return 1
}
# If the first globals section has alt_config_file, don't process any more globals
[ -z "$HAVE_ALT_CONF_FILE" ] || return 0
# If "alt_config_file" specified in the first globals section, use that instead
[ -z "$alt_config_file" ] || [ -n "$CONF_FILE_CREATED" ] || {
# Symlink "alt_config_file" since it's a bit easier and safer
ln -s "$alt_config_file" "$CONF_FILE"
# Set section found to start service, user hopefully knows what they are doing
SERVICE_SECTION_FOUND=1
CONF_FILE_CREATED=1
HAVE_ALT_CONF_FILE=1
return 0
}
pid_dir="$(dirname "$PID_FILE")"
mkdir -p "$pid_dir"
[ -z "$setuid" ] || chown "$setuid" "$pid_dir"
[ -z "$setgid" ] || chown ":$setgid" "$pid_dir"
create_conf_file
print_global_options
validate_service_options globals "$1" print_service_options
}
service_section() {
[ "$2" = 0 ] || {
echo "validation failed"
return 1
}
[ "$enabled" = 1 ] || return 0
SERVICE_SECTION_FOUND=1
echo >> "$CONF_FILE"
echo "[$1]" >> "$CONF_FILE"
validate_service_options service "$1" print_service_options
}
service_triggers() {
procd_add_reload_trigger stunnel
procd_open_validate
validate_globals_section
validate_globals_section_service_options
validate_service_section
validate_service_section_service_options
procd_close_validate
}
start_service() {
rm -f "$CONF_FILE"
config_load stunnel
config_foreach validate_globals_section globals global_defs
[ -n "$HAVE_ALT_CONF_FILE" ] || {
create_conf_file
config_foreach validate_service_section service service_section
}
[ -n "$SERVICE_SECTION_FOUND" ] || {
logger -t stunnel -p daemon.info "No uci service section enabled or found!"
return 1
}
procd_open_instance
procd_set_param command "$BIN"
procd_append_param command "$CONF_FILE"
procd_set_param respawn
procd_set_param file "$CONF_FILE"
procd_close_instance
}