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

  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. 'ticketKeySecret:string' \
  100. 'ticketMacSecret:string' \
  101. 'TIMEOUTbusy:uinteger' \
  102. 'TIMEOUTclose:uinteger' \
  103. 'TIMEOUTconnect:uinteger' \
  104. 'TIMEOUTidle:uinteger' \
  105. 'transparent:or("both","destination","none","source")' \
  106. 'verifyChain:bool' \
  107. 'verifyPeer:bool' \
  108. ;
  109. }
  110. validate_globals_section_service_options() {
  111. validate_service_options globals "$@"
  112. }
  113. validate_service_section_service_options() {
  114. validate_service_options service "$@"
  115. }
  116. print_options() {
  117. local _opt
  118. local _value
  119. for _opt in $*; do
  120. eval "_value=\$$_opt"
  121. [ -z "$_value" ] || echo "$_opt = $_value" >> "$CONF_FILE"
  122. done
  123. }
  124. print_bool_options() {
  125. local _opt
  126. local _bool
  127. local _value
  128. for _opt in $*; do
  129. eval "_bool=\$$_opt"
  130. [ -z "$_bool" ] || {
  131. _value=no
  132. [ "$_bool" != 1 ] || _value=yes
  133. echo "$_opt = $_value" >> "$CONF_FILE"
  134. }
  135. done
  136. }
  137. print_lists_map() {
  138. local _opt
  139. local _values
  140. local _value
  141. for _opt in $*; do
  142. eval "_values=\$$_opt"
  143. for _value in $_values; do
  144. echo "$_opt = $_value" >> "$CONF_FILE"
  145. done
  146. done
  147. }
  148. print_lists_reduce() {
  149. local _delim="$1"
  150. local _opt
  151. local _value
  152. local _values
  153. local _v
  154. shift
  155. for _opt in $*; do
  156. _value=
  157. eval "_values=\$$_opt"
  158. for _v in $_values; do
  159. _value=$_value$_delim$_v
  160. done
  161. _value=${_value#$_delim}
  162. [ -z "$_value" ] || echo "$_opt = $_value" >> "$CONF_FILE"
  163. done
  164. }
  165. print_host_port() {
  166. local _opt
  167. local _host
  168. local _port
  169. for _opt in $*; do
  170. eval "_host=\${${_opt}_host}"
  171. eval "_port=\${${_opt}_port}"
  172. [ -z "$_host" ] || [ -z "$_port" ] || echo "$_opt = $_host:$_port" >> "$CONF_FILE"
  173. done
  174. }
  175. print_optional_host_port() {
  176. local _opt
  177. local _host
  178. local _port
  179. local _value
  180. for _opt in $*; do
  181. eval "_host=\${${_opt}_host}"
  182. eval "_port=\${${_opt}_port}"
  183. [ -z "$_port" ] || {
  184. _value=$_port
  185. [ -z "$_host" ] || _value=$_host:$_port
  186. echo "$_opt = $_value" >> "$CONF_FILE"
  187. }
  188. done
  189. }
  190. print_global_options() {
  191. print_options \
  192. compression \
  193. EGD \
  194. engine \
  195. engineCtrl \
  196. log \
  197. output \
  198. RNDbytes \
  199. RNDfile \
  200. RNDoverwrite \
  201. ;
  202. print_bool_options \
  203. syslog \
  204. ;
  205. print_lists_reduce , \
  206. engineDefault \
  207. ;
  208. }
  209. print_service_options() {
  210. [ "$2" = 0 ] || {
  211. echo "validation failed"
  212. return 1
  213. }
  214. print_options \
  215. CAfile \
  216. CApath \
  217. cert \
  218. CRLfile \
  219. CRLpath \
  220. debug \
  221. logId \
  222. engineId \
  223. engineNum \
  224. exec \
  225. execArgs \
  226. failover \
  227. ident \
  228. include \
  229. key \
  230. local \
  231. OCSP \
  232. protocol \
  233. protocolAuthentication \
  234. protocolDomain \
  235. protocolPassword \
  236. protocolUsername \
  237. PSKidentity \
  238. PSKsecrets \
  239. service \
  240. sessionCacheSize \
  241. sessionCacheTimeout \
  242. setgid \
  243. setuid \
  244. sslVersion \
  245. stack \
  246. ticketKeySecret \
  247. ticketMacSecret \
  248. TIMEOUTbusy \
  249. TIMEOUTclose \
  250. TIMEOUTconnect \
  251. TIMEOUTidle \
  252. transparent \
  253. ;
  254. print_bool_options \
  255. client \
  256. delay \
  257. OCSPaia \
  258. OCSPnonce \
  259. pty \
  260. renegotiation \
  261. requireCert \
  262. reset \
  263. retry \
  264. verifyChain \
  265. verifyPeer \
  266. ;
  267. print_lists_map \
  268. checkEmail \
  269. checkHost \
  270. checkIP \
  271. config \
  272. connect \
  273. OCSPflag \
  274. options \
  275. sni \
  276. socket \
  277. ;
  278. print_lists_reduce : \
  279. ciphers \
  280. curves \
  281. ciphersuites \
  282. ;
  283. print_host_port \
  284. protocolHost \
  285. sessiond \
  286. ;
  287. print_optional_host_port \
  288. accept \
  289. redirect \
  290. ;
  291. }
  292. create_conf_file() {
  293. [ -n "$CONF_FILE_CREATED" ] || {
  294. mkdir -p "$(dirname "$CONF_FILE")"
  295. echo "; STunnel configuration file generated by uci" > "$CONF_FILE"
  296. echo "; Written $(date +'%c')" >> "$CONF_FILE"
  297. echo >> "$CONF_FILE"
  298. echo "foreground = quiet" >> "$CONF_FILE"
  299. echo "pid = $PID_FILE" >> "$CONF_FILE"
  300. CONF_FILE_CREATED=1
  301. }
  302. }
  303. global_defs() {
  304. local pid_dir
  305. [ "$2" = 0 ] || {
  306. echo "validation failed"
  307. return 1
  308. }
  309. # If the first globals section has alt_config_file, don't process any more globals
  310. [ -z "$HAVE_ALT_CONF_FILE" ] || return 0
  311. # If "alt_config_file" specified in the first globals section, use that instead
  312. [ -z "$alt_config_file" ] || [ -n "$CONF_FILE_CREATED" ] || {
  313. # Symlink "alt_config_file" since it's a bit easier and safer
  314. ln -s "$alt_config_file" "$CONF_FILE"
  315. # Set section found to start service, user hopefully knows what they are doing
  316. SERVICE_SECTION_FOUND=1
  317. CONF_FILE_CREATED=1
  318. HAVE_ALT_CONF_FILE=1
  319. return 0
  320. }
  321. pid_dir="$(dirname "$PID_FILE")"
  322. mkdir -p "$pid_dir"
  323. [ -z "$setuid" ] || chown "$setuid" "$pid_dir"
  324. [ -z "$setgid" ] || chown ":$setgid" "$pid_dir"
  325. create_conf_file
  326. print_global_options
  327. validate_service_options globals "$1" print_service_options
  328. }
  329. service_section() {
  330. [ "$2" = 0 ] || {
  331. echo "validation failed"
  332. return 1
  333. }
  334. [ "$enabled" = 1 ] || return 0
  335. SERVICE_SECTION_FOUND=1
  336. echo >> "$CONF_FILE"
  337. echo "[$1]" >> "$CONF_FILE"
  338. validate_service_options service "$1" print_service_options
  339. }
  340. service_triggers() {
  341. procd_add_reload_trigger stunnel
  342. procd_open_validate
  343. validate_globals_section
  344. validate_globals_section_service_options
  345. validate_service_section
  346. validate_service_section_service_options
  347. procd_close_validate
  348. }
  349. start_service() {
  350. rm -f "$CONF_FILE"
  351. config_load stunnel
  352. config_foreach validate_globals_section globals global_defs
  353. [ -n "$HAVE_ALT_CONF_FILE" ] || {
  354. create_conf_file
  355. config_foreach validate_service_section service service_section
  356. }
  357. [ -n "$SERVICE_SECTION_FOUND" ] || {
  358. logger -t stunnel -p daemon.info "No uci service section enabled or found!"
  359. return 1
  360. }
  361. procd_open_instance
  362. procd_set_param command "$BIN"
  363. procd_append_param command "$CONF_FILE"
  364. procd_set_param respawn
  365. procd_set_param file "$CONF_FILE"
  366. procd_close_instance
  367. }