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.

425 lines
9.4 KiB

  1. #!/bin/sh /etc/rc.common
  2. # Copyright (C) 2012-2013 OpenWrt.org
  3. START=95
  4. SERVICE_USE_PID=1
  5. EXTRA_COMMANDS="up down show_key generate_key"
  6. LIST_SEP="
  7. "
  8. TMP_FASTD=/tmp/fastd
  9. FASTD_COMMAND=/usr/bin/fastd
  10. section_enabled() {
  11. config_get_bool enabled "$1" 'enabled' 0
  12. [ $enabled -gt 0 ]
  13. }
  14. error() {
  15. echo "${initscript}:" "$@" 1>&2
  16. }
  17. get_key_instance() {
  18. local s="$1"
  19. config_get secret "$s" secret
  20. if [ "$secret" = 'generate' ]; then
  21. secret=`"$FASTD_COMMAND" --generate-key --machine-readable`
  22. uci -q set fastd."$s".secret="$secret" && uci -q commit fastd
  23. fi
  24. echo "$secret"
  25. }
  26. escape_string() {
  27. local t=${1//\\/\\\\}
  28. echo -n "\"${t//\"/\\\"}\""
  29. }
  30. guard_value() {
  31. local t=${1//[^-a-z0-9\[\].:]/}
  32. echo -n "$t"
  33. }
  34. guard_remote() {
  35. local t=${1//[^-a-zA-Z0-9\[\].:\"% ]/}
  36. local quotes=${t//[^\"]/}
  37. if [ "${#quotes}" = 0 -o "${#quotes}" = 2 ]; then
  38. echo -n "$t"
  39. fi
  40. }
  41. yes_no() {
  42. case "$1" in
  43. 0|no|off|false|disabled) echo -n no;;
  44. *) echo -n yes;;
  45. esac
  46. }
  47. config_string_config='include $(escape_string "$value");'
  48. config_string_config_peer='include peer $(escape_string "$value");'
  49. config_string_config_peer_dir='include peers from $(escape_string "$value");'
  50. config_string_bind='bind $(guard_value "$value");'
  51. config_string_method='method $(escape_string "$value");'
  52. config_string_syslog_level='log to syslog level $(guard_value "$value");'
  53. config_string_mode='mode $(guard_value "$value");'
  54. config_string_interface='interface $(escape_string "$value");'
  55. config_string_mtu='mtu $(guard_value "$value");'
  56. config_string_peer_limit='peer limit $(guard_value "$value");'
  57. config_string_user='user $(escape_string "$value");'
  58. config_string_group='group $(escape_string "$value");'
  59. config_string_pmtu='pmtu $(yes_no "$value");'
  60. config_string_forward='forward $(yes_no "$value");'
  61. config_string_hide_ip_addresses='hide ip addresses $(yes_no "$value");'
  62. config_string_hide_mac_addresses='hide mac addresses $(yes_no "$value");'
  63. config_string_secure_handshakes='secure handshakes $(yes_no "$value");'
  64. config_string_packet_mark='packet mark $(guard_value "$value");'
  65. config_string_peer='peer $(escape_string "$value") {'
  66. config_string_peer_group='peer group $(escape_string "$value") {'
  67. peer_string_key='key $(escape_string "$value");'
  68. peer_string_float='float $(yes_no "$value");'
  69. peer_string_remote='remote $(guard_remote "$value");'
  70. generate_option() {
  71. local __string=$(eval echo \"\$$2\")
  72. local value="$1";
  73. eval echo "\"$__string\""
  74. }
  75. append_option() {
  76. local v; local len; local s="$1"; local prefix="$2"; local p="$3"
  77. config_get len "$s" "${p}_LENGTH"
  78. if [ -z "$len" ]; then
  79. config_get v "$s" "$p"
  80. [ -n "$v" ] && generate_option "$v" "${prefix}_string_${p}"
  81. else
  82. config_list_foreach "$s" "$p" generate_option "${prefix}_string_${p}"
  83. fi
  84. }
  85. append_options() {
  86. local p; local s="$1"; local prefix="$2"; shift; shift
  87. for p in $*; do
  88. append_option "$s" "$prefix" "$p"
  89. done
  90. }
  91. generate_config_secret() {
  92. echo "secret $(escape_string "$1");"
  93. }
  94. generate_peer_config() {
  95. local peer="$1"
  96. # These options are deprecated
  97. config_get address "$peer" address
  98. config_get hostname "$peer" hostname
  99. config_get address_family "$peer" address_family
  100. config_get port "$peer" port
  101. if [ "$address" -o "$hostname" ]; then
  102. if [ -z "$port" ]; then
  103. error "peer $peer: address or hostname, but no port given"
  104. return 1
  105. fi
  106. if [ "$hostname" ]; then
  107. generate_option peer_string_remote "$address_family \"$hostname\" port $port"
  108. fi
  109. if [ "$address" ]; then
  110. generate_option peer_string_remote "$address port $port"
  111. fi
  112. fi
  113. append_options "$peer" peer \
  114. key float remote
  115. }
  116. generate_single_peer_config() {
  117. local peer="$1"; local net="$2"
  118. config_get peer_net "$peer" net
  119. config_get peer_group "$peer" group
  120. [ "$net" = "$peer_net" -a "$peer_group" = '' ] || return 0
  121. section_enabled "$peer" || return 0
  122. generate_option "$peer" config_string_peer
  123. generate_peer_config "$peer"
  124. echo '}'
  125. }
  126. create_peer_config() {
  127. local peer="$1"; local net="$2"; local group="$3"; local path="$4"
  128. config_get peer_net "$peer" net
  129. config_get peer_group "$peer" group
  130. [ "$group" = "$peer_group" ] || return 0
  131. if [ "$net" != "$peer_net" ]; then
  132. [ -z "$group" ] || error "warning: the peer group of peer '$peer' doesn't match its net, the peer will be ignored"
  133. return 0
  134. fi
  135. section_enabled "$peer" || return 0
  136. generate_peer_config "$peer" >"$path/$peer"
  137. }
  138. update_peer_group() {
  139. local net="$1"; local group_dir="$2"; local group="$3"; local update_only="$4"
  140. local path="$TMP_FASTD/fastd.$net/$group_dir"
  141. rm -rf "$path"
  142. mkdir -p "$path"
  143. config_foreach create_peer_config 'peer' "$net" "$group" "$path"
  144. if [ -z "$update_only" ]; then
  145. generate_option "$path" config_string_config_peer_dir
  146. fi
  147. config_foreach generate_peer_group_config 'peer_group' "$net" "$group_dir" "$update_only" "$group"
  148. }
  149. generate_peer_group_config() {
  150. local group="$1"; local net="$2"; local group_dir="$3%$group"; local update_only="$4"; local parent="$5"
  151. config_get group_net "$group" net
  152. config_get group_parent "$group" parent
  153. [ "$parent" = "$group_parent" ] || return 0
  154. if [ "$net" != "$peer_net" ]; then
  155. [ -z "$parent" ] || error "warning: the parent of peer group '$group' doesn't match its net, the peer group will be ignored"
  156. return 0
  157. fi
  158. section_enabled "$group" || return 0
  159. if [ -z "$update_only" ]; then
  160. generate_option "$group" config_string_peer_group
  161. append_options "$group" config \
  162. config config_peer config_peer_dir peer_limit
  163. fi
  164. update_peer_group "$net" "$group_dir" "$group" "$update_only"
  165. if [ -z "$update_only" ]; then
  166. echo '}'
  167. fi
  168. }
  169. update_peer_groups() {
  170. local net="$1"; local update_only="$2"
  171. update_peer_group "$net" 'peers' '' "$update_only"
  172. }
  173. generate_config() {
  174. local s="$1"
  175. generate_option 'info' config_string_syslog_level
  176. append_options "$s" config \
  177. config config_peer config_peer_dir bind method syslog_level mode interface mtu peer_limit \
  178. user group pmtu forward hide_ip_addresses hide_mac_addresses secure_handshakes packet_mark
  179. config_get mode "$s" mode
  180. if [ "$mode" = "tun" ]; then
  181. config_foreach generate_single_peer_config 'peer' "$s"
  182. else
  183. update_peer_groups "$s"
  184. fi
  185. }
  186. generate_key_instance() {
  187. local s="$1"
  188. config_get secret "$s" secret
  189. if [ -z "$secret" -o "$secret" = 'generate' ]; then
  190. secret=`fastd --generate-key --machine-readable`
  191. uci -q set fastd."$s".secret="$secret" && uci -q commit fastd
  192. fi
  193. generate_config_secret "$secret" | "$FASTD_COMMAND" --config - --show-key --machine-readable
  194. }
  195. show_key_instance() {
  196. local s="$1"
  197. local secret=`get_key_instance "$s"`
  198. if [ -z "$secret" ]; then
  199. error "$s: secret is not set"
  200. return 1
  201. fi
  202. generate_config_secret "$secret" | "$FASTD_COMMAND" --config - --show-key --machine-readable
  203. }
  204. start_instance() {
  205. local s="$1"
  206. section_enabled "$s" || return 1
  207. SERVICE_PID_FILE="/var/run/fastd.$s.pid"
  208. config_get interface "$s" interface
  209. if [ -z "$interface" ]; then
  210. error "$s: interface is not set"
  211. return 1
  212. fi
  213. if ifconfig "$interface" &>/dev/null; then
  214. error "$s: interface '$interface' is already in use"
  215. return 1
  216. fi
  217. config_get mode "$s" mode
  218. if [ -z "$mode" ]; then
  219. error "$s: mode is not set"
  220. return 1
  221. fi
  222. local secret=`get_key_instance "$s"`
  223. if [ -z "$secret" ]; then
  224. error "$s: secret is not set"
  225. return 1
  226. fi
  227. rm -f "$SERVICE_PID_FILE"
  228. touch "$SERVICE_PID_FILE"
  229. config_get user "$s" user
  230. if [ "$user" ]; then
  231. chown "$user" "$SERVICE_PID_FILE"
  232. fi
  233. (generate_config_secret "$secret"; generate_config "$s") | service_start "$FASTD_COMMAND" --config - --daemon --pid-file "$SERVICE_PID_FILE"
  234. if ! ifconfig "$interface" >/dev/null 2>&1; then
  235. error "$s: startup failed"
  236. return 1
  237. fi
  238. config_get up "$s" up
  239. [ -n "$up" ] && sh -c "$up" - "$interface"
  240. }
  241. stop_instance() {
  242. local s="$1"
  243. section_enabled "$s" || return 1
  244. SERVICE_PID_FILE="/var/run/fastd.$s.pid"
  245. config_get interface "$s" interface
  246. if [ -z "$interface" ]; then
  247. error "$s: interface is not set"
  248. return 1
  249. fi
  250. if ! ifconfig "$interface" &>/dev/null; then
  251. error "$s: interface '$interface' does not exist"
  252. return 1
  253. fi
  254. config_get down "$s" down
  255. [ -n "$down" ] && sh -c "$down" - "$interface"
  256. service_stop "$FASTD_COMMAND"
  257. rm -rf "$TMP_FASTD/fastd.$s"
  258. }
  259. reload_instance() {
  260. local s="$1"
  261. section_enabled "$s" || return 1
  262. config_get mode "$s" mode
  263. [ "$mode" = "tun" ] && return 1
  264. update_peer_groups "$s" true
  265. SERVICE_PID_FILE="/var/run/fastd.$s.pid"
  266. service_reload "$FASTD_COMMAND"
  267. }
  268. start() {
  269. config_load 'fastd'
  270. config_foreach start_instance 'fastd'
  271. return 0
  272. }
  273. stop() {
  274. config_load 'fastd'
  275. config_foreach stop_instance 'fastd'
  276. return 0
  277. }
  278. reload() {
  279. config_load 'fastd'
  280. config_foreach reload_instance 'fastd'
  281. return 0
  282. }
  283. up() {
  284. local exists
  285. local instance
  286. config_load 'fastd'
  287. for instance in "$@"; do
  288. config_get exists "$instance" 'TYPE'
  289. if [ "$exists" = 'fastd' ]; then
  290. start_instance "$instance"
  291. fi
  292. done
  293. }
  294. down() {
  295. local exists
  296. local instance
  297. config_load 'fastd'
  298. for instance in "$@"; do
  299. config_get exists "$instance" 'TYPE'
  300. if [ "$exists" = 'fastd' ]; then
  301. stop_instance "$instance"
  302. fi
  303. done
  304. }
  305. show_key() {
  306. local exists
  307. local instance
  308. config_load 'fastd'
  309. for instance in "$@"; do
  310. config_get exists "$instance" 'TYPE'
  311. if [ "$exists" = 'fastd' ]; then
  312. show_key_instance "$instance"
  313. fi
  314. done
  315. }
  316. generate_key() {
  317. local exists
  318. local instance
  319. config_load 'fastd'
  320. for instance in "$@"; do
  321. config_get exists "$instance" 'TYPE'
  322. if [ "$exists" = 'fastd' ]; then
  323. generate_key_instance "$instance"
  324. fi
  325. done
  326. }