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.

404 lines
8.1 KiB

  1. #!/bin/sh /etc/rc.common
  2. # Copyright (C) 2006-2008 OpenWrt.org
  3. # Copyright (C) 2019 Jeffery To
  4. START=90
  5. USE_PROCD=1
  6. PID_FILE="/var/run/stunnel/stunnel.pid"
  7. CONF_FILE="/var/etc/stunnel.conf"
  8. BIN="/usr/bin/stunnel"
  9. CONF_FILE_CREATED=
  10. HAVE_ALT_CONF_FILE=
  11. SERVICE_SECTION_FOUND=
  12. validate_globals_section() {
  13. uci_load_validate stunnel globals "$1" "$2" \
  14. 'alt_config_file:file' \
  15. \
  16. 'compression:or("deflate","zlib")' \
  17. 'EGD:string' \
  18. 'engine:string' \
  19. 'engineCtrl:string' \
  20. 'engineDefault:list(or("ALL","CIPHERS","DH","DIGESTS","DSA","ECDH","ECDSA","PKEY","PKEY_ASN1","PKEY_CRYPTO","RAND","RSA"))' \
  21. 'log:or("append","overwrite")' \
  22. 'output:string' \
  23. 'RNDbytes:uinteger' \
  24. 'RNDfile:string' \
  25. 'RNDoverwrite:bool' \
  26. 'setgid:or(string,uinteger)' \
  27. 'setuid:or(string,uinteger)' \
  28. 'syslog:bool' \
  29. ;
  30. }
  31. validate_service_section() {
  32. uci_load_validate stunnel service "$1" "$2" \
  33. 'enabled:bool:1' \
  34. \
  35. 'setgid:or(string,uinteger)' \
  36. 'setuid:or(string,uinteger)' \
  37. ;
  38. }
  39. validate_service_options() {
  40. uci_load_validate stunnel "$1" "$2" "$3" \
  41. 'accept_host:host' \
  42. 'accept_port:port' \
  43. 'CAfile:string' \
  44. 'CApath:string' \
  45. 'cert:string' \
  46. 'checkEmail:list(string)' \
  47. 'checkHost:list(host)' \
  48. 'checkIP:list(ipaddr)' \
  49. 'ciphers:list(string)' \
  50. 'ciphersuites:list(string)' \
  51. 'client:bool' \
  52. 'config:list(string)' \
  53. 'connect:list(string)' \
  54. 'CRLfile:string' \
  55. 'CRLpath:string' \
  56. 'curves:list(string)' \
  57. 'debug:or(range(0,7),string)' \
  58. 'delay:bool' \
  59. 'engineId:string' \
  60. 'engineNum:and(uinteger,min(1))' \
  61. 'exec:string' \
  62. 'execArgs:string' \
  63. 'failover:or("prio","rr")' \
  64. 'ident:string' \
  65. 'include:directory' \
  66. 'key:string' \
  67. 'local:host' \
  68. 'logId:or("process","sequential","thread","unique")' \
  69. 'OCSP:string' \
  70. 'OCSPaia:bool' \
  71. 'OCSPflag:list(or("NOCASIGN","NOCERTS","NOCHAIN","NOCHECKS","NODELEGATED","NOEXPLICIT","NOINTERN","NOSIGS","NOTIME","NOVERIFY","RESPID_KEY","TRUSTOTHER"))' \
  72. 'OCSPnonce:bool' \
  73. 'options:list(string) ' \
  74. 'protocol:or("cifs","connect","imap","nntp","pgsql","pop3","proxy","smtp","socks")' \
  75. 'protocolAuthentication:or("basic","login","ntlm","plain")' \
  76. 'protocolDomain:hostname' \
  77. 'protocolHost_host:host' \
  78. 'protocolHost_port:port' \
  79. 'protocolPassword:string' \
  80. 'protocolUsername:string' \
  81. 'PSKidentity:string' \
  82. 'PSKsecrets:string' \
  83. 'pty:bool' \
  84. 'redirect_host:host' \
  85. 'redirect_port:port' \
  86. 'renegotiation:bool' \
  87. 'requireCert:bool' \
  88. 'reset:bool' \
  89. 'retry:bool' \
  90. 'service:string' \
  91. 'sessionCacheSize:uinteger' \
  92. 'sessionCacheTimeout:uinteger' \
  93. 'sessiond_host:host' \
  94. 'sessiond_port:port' \
  95. 'sni:list(string)' \
  96. 'socket:list(string)' \
  97. 'sslVersion:or("all","SSLv2","SSLv3","TLSv1","TLSv1.1","TLSv1.2")' \
  98. 'stack:uinteger' \
  99. 'TIMEOUTbusy:uinteger' \
  100. 'TIMEOUTclose:uinteger' \
  101. 'TIMEOUTconnect:uinteger' \
  102. 'TIMEOUTidle:uinteger' \
  103. 'transparent:or("both","destination","none","source")' \
  104. 'verifyChain:bool' \
  105. 'verifyPeer:bool' \
  106. ;
  107. }
  108. validate_globals_section_service_options() {
  109. validate_service_options globals "$@"
  110. }
  111. validate_service_section_service_options() {
  112. validate_service_options service "$@"
  113. }
  114. print_options() {
  115. local _opt
  116. local _value
  117. for _opt in $*; do
  118. eval "_value=\$$_opt"
  119. [ -z "$_value" ] || echo "$_opt = $_value" >> "$CONF_FILE"
  120. done
  121. }
  122. print_bool_options() {
  123. local _opt
  124. local _bool
  125. local _value
  126. for _opt in $*; do
  127. eval "_bool=\$$_opt"
  128. [ -z "$_bool" ] || {
  129. _value=no
  130. [ "$_bool" != 1 ] || _value=yes
  131. echo "$_opt = $_value" >> "$CONF_FILE"
  132. }
  133. done
  134. }
  135. print_lists_map() {
  136. local _opt
  137. local _values
  138. local _value
  139. for _opt in $*; do
  140. eval "_values=\$$_opt"
  141. for _value in $_values; do
  142. echo "$_opt = $_value" >> "$CONF_FILE"
  143. done
  144. done
  145. }
  146. print_lists_reduce() {
  147. local _delim="$1"
  148. local _opt
  149. local _value
  150. local _values
  151. local _v
  152. shift
  153. for _opt in $*; do
  154. _value=
  155. eval "_values=\$$_opt"
  156. for _v in $_values; do
  157. _value=$_value$_delim$_v
  158. done
  159. _value=${_value#$_delim}
  160. [ -z "$_value" ] || echo "$_opt = $_value" >> "$CONF_FILE"
  161. done
  162. }
  163. print_host_port() {
  164. local _opt
  165. local _host
  166. local _port
  167. for _opt in $*; do
  168. eval "_host=\${${_opt}_host}"
  169. eval "_port=\${${_opt}_port}"
  170. [ -z "$_host" ] || [ -z "$_port" ] || echo "$_opt = $_host:$_port" >> "$CONF_FILE"
  171. done
  172. }
  173. print_optional_host_port() {
  174. local _opt
  175. local _host
  176. local _port
  177. local _value
  178. for _opt in $*; do
  179. eval "_host=\${${_opt}_host}"
  180. eval "_port=\${${_opt}_port}"
  181. [ -z "$_port" ] || {
  182. _value=$_port
  183. [ -z "$_host" ] || _value=$_host:$_port
  184. echo "$_opt = $_value" >> "$CONF_FILE"
  185. }
  186. done
  187. }
  188. print_global_options() {
  189. print_options \
  190. compression \
  191. EGD \
  192. engine \
  193. engineCtrl \
  194. log \
  195. output \
  196. RNDbytes \
  197. RNDfile \
  198. RNDoverwrite \
  199. ;
  200. print_bool_options \
  201. syslog \
  202. ;
  203. print_lists_reduce , \
  204. engineDefault \
  205. ;
  206. }
  207. print_service_options() {
  208. [ "$2" = 0 ] || {
  209. echo "validation failed"
  210. return 1
  211. }
  212. print_options \
  213. CAfile \
  214. CApath \
  215. cert \
  216. CRLfile \
  217. CRLpath \
  218. debug \
  219. logId \
  220. engineId \
  221. engineNum \
  222. exec \
  223. execArgs \
  224. failover \
  225. ident \
  226. include \
  227. key \
  228. local \
  229. OCSP \
  230. protocol \
  231. protocolAuthentication \
  232. protocolDomain \
  233. protocolPassword \
  234. protocolUsername \
  235. PSKidentity \
  236. PSKsecrets \
  237. service \
  238. sessionCacheSize \
  239. sessionCacheTimeout \
  240. setgid \
  241. setuid \
  242. sslVersion \
  243. stack \
  244. TIMEOUTbusy \
  245. TIMEOUTclose \
  246. TIMEOUTconnect \
  247. TIMEOUTidle \
  248. transparent \
  249. ;
  250. print_bool_options \
  251. client \
  252. delay \
  253. OCSPaia \
  254. OCSPnonce \
  255. pty \
  256. renegotiation \
  257. requireCert \
  258. reset \
  259. retry \
  260. verifyChain \
  261. verifyPeer \
  262. ;
  263. print_lists_map \
  264. checkEmail \
  265. checkHost \
  266. checkIP \
  267. config \
  268. connect \
  269. OCSPflag \
  270. options \
  271. sni \
  272. socket \
  273. ;
  274. print_lists_reduce : \
  275. ciphers \
  276. curves \
  277. ciphersuites \
  278. ;
  279. print_host_port \
  280. protocolHost \
  281. sessiond \
  282. ;
  283. print_optional_host_port \
  284. accept \
  285. redirect \
  286. ;
  287. }
  288. create_conf_file() {
  289. [ -n "$CONF_FILE_CREATED" ] || {
  290. mkdir -p "$(dirname "$CONF_FILE")"
  291. echo "; STunnel configuration file generated by uci" > "$CONF_FILE"
  292. echo "; Written $(date +'%c')" >> "$CONF_FILE"
  293. echo >> "$CONF_FILE"
  294. echo "foreground = quiet" >> "$CONF_FILE"
  295. echo "pid = $PID_FILE" >> "$CONF_FILE"
  296. CONF_FILE_CREATED=1
  297. }
  298. }
  299. global_defs() {
  300. local pid_dir
  301. [ "$2" = 0 ] || {
  302. echo "validation failed"
  303. return 1
  304. }
  305. # If the first globals section has alt_config_file, don't process any more globals
  306. [ -z "$HAVE_ALT_CONF_FILE" ] || return 0
  307. # If "alt_config_file" specified in the first globals section, use that instead
  308. [ -z "$alt_config_file" ] || [ -n "$CONF_FILE_CREATED" ] || {
  309. # Symlink "alt_config_file" since it's a bit easier and safer
  310. ln -s "$alt_config_file" "$CONF_FILE"
  311. # Set section found to start service, user hopefully knows what they are doing
  312. SERVICE_SECTION_FOUND=1
  313. CONF_FILE_CREATED=1
  314. HAVE_ALT_CONF_FILE=1
  315. return 0
  316. }
  317. pid_dir="$(dirname "$PID_FILE")"
  318. mkdir -p "$pid_dir"
  319. [ -z "$setuid" ] || chown "$setuid" "$pid_dir"
  320. [ -z "$setgid" ] || chown ":$setgid" "$pid_dir"
  321. create_conf_file
  322. print_global_options
  323. validate_service_options globals "$1" print_service_options
  324. }
  325. service_section() {
  326. [ "$2" = 0 ] || {
  327. echo "validation failed"
  328. return 1
  329. }
  330. [ "$enabled" = 1 ] || return 0
  331. SERVICE_SECTION_FOUND=1
  332. echo >> "$CONF_FILE"
  333. echo "[$1]" >> "$CONF_FILE"
  334. validate_service_options service "$1" print_service_options
  335. }
  336. service_triggers() {
  337. procd_add_reload_trigger stunnel
  338. procd_open_validate
  339. validate_globals_section
  340. validate_globals_section_service_options
  341. validate_service_section
  342. validate_service_section_service_options
  343. procd_close_validate
  344. }
  345. start_service() {
  346. rm -f "$CONF_FILE"
  347. config_load stunnel
  348. config_foreach validate_globals_section globals global_defs
  349. [ -n "$HAVE_ALT_CONF_FILE" ] || {
  350. create_conf_file
  351. config_foreach validate_service_section service service_section
  352. }
  353. [ -n "$SERVICE_SECTION_FOUND" ] || {
  354. logger -t stunnel -p daemon.info "No uci service section enabled or found!"
  355. return 1
  356. }
  357. procd_open_instance
  358. procd_set_param command "$BIN"
  359. procd_append_param command "$CONF_FILE"
  360. procd_set_param respawn
  361. procd_set_param file "$CONF_FILE"
  362. procd_close_instance
  363. }